cmd/gomobile: support manifest screenOrientation
Testing BinaryXML for the change was non-trivial as the first 4 bytes of gomobile output did not match the latest version of aapt's output. A new approach to testing compatibility was added based on how the aapt tool pretty prints xmltree of manifest's contents. Fixes golang/go#10943 Change-Id: I5c60af10931d9693dbeaff66f23a69042a78e8fa Reviewed-on: https://go-review.googlesource.com/16150 Reviewed-by: David Crawshaw <crawshaw@golang.org> Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
Родитель
1b12574c99
Коммит
103b3cfae8
|
@ -237,16 +237,17 @@ func appendHeader(b []byte, typ headerType, size int) []byte {
|
|||
//
|
||||
// http://developer.android.com/reference/android/R.attr.html
|
||||
var resourceCodes = map[string]uint32{
|
||||
"versionCode": 0x0101021b,
|
||||
"versionName": 0x0101021c,
|
||||
"minSdkVersion": 0x0101020c,
|
||||
"windowFullscreen": 0x0101020d,
|
||||
"label": 0x01010001,
|
||||
"hasCode": 0x0101000c,
|
||||
"debuggable": 0x0101000f,
|
||||
"name": 0x01010003,
|
||||
"configChanges": 0x0101001f,
|
||||
"value": 0x01010024,
|
||||
"versionCode": 0x0101021b,
|
||||
"versionName": 0x0101021c,
|
||||
"minSdkVersion": 0x0101020c,
|
||||
"windowFullscreen": 0x0101020d,
|
||||
"label": 0x01010001,
|
||||
"hasCode": 0x0101000c,
|
||||
"debuggable": 0x0101000f,
|
||||
"name": 0x01010003,
|
||||
"screenOrientation": 0x0101001e,
|
||||
"configChanges": 0x0101001f,
|
||||
"value": 0x01010024,
|
||||
}
|
||||
|
||||
// http://developer.android.com/reference/android/R.attr.html#configChanges
|
||||
|
@ -267,6 +268,26 @@ var configChanges = map[string]uint32{
|
|||
"fontScale": 0x40000000,
|
||||
}
|
||||
|
||||
// http://developer.android.com/reference/android/R.attr.html#screenOrientation
|
||||
var screenOrientation = map[string]int{
|
||||
"unspecified": -1,
|
||||
"landscape": 0,
|
||||
"portrait": 1,
|
||||
"user": 2,
|
||||
"behind": 3,
|
||||
"sensor": 4,
|
||||
"nosensor": 5,
|
||||
"sensorLandscape": 6,
|
||||
"sensorPortrait": 7,
|
||||
"reverseLandscape": 8,
|
||||
"reversePortrait": 9,
|
||||
"fullSensor": 10,
|
||||
"userLandscape": 11,
|
||||
"userPortrait": 12,
|
||||
"fullUser": 13,
|
||||
"locked": 14,
|
||||
}
|
||||
|
||||
type lineReader struct {
|
||||
off int64
|
||||
lines []int64
|
||||
|
@ -400,6 +421,12 @@ func (p *binStringPool) getAttr(attr xml.Attr) (*binAttr, error) {
|
|||
v |= configChanges[c]
|
||||
}
|
||||
a.data = v
|
||||
case "screenOrientation":
|
||||
v := 0
|
||||
for _, c := range strings.Split(attr.Value, "|") {
|
||||
v |= screenOrientation[c]
|
||||
}
|
||||
a.data = v
|
||||
default:
|
||||
a.data = p.get(attr.Value)
|
||||
}
|
||||
|
|
|
@ -5,10 +5,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -23,33 +27,83 @@ func TestBinaryXML(t *testing.T) {
|
|||
sortPool, sortAttr = sortToMatchTest, sortAttrToMatchTest
|
||||
defer func() { sortPool, sortAttr = origSortPool, origSortAttr }()
|
||||
|
||||
got, err := binaryXML(bytes.NewBufferString(input))
|
||||
bin, err := binaryXML(bytes.NewBufferString(input))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if *dump {
|
||||
if err := ioutil.WriteFile("junk.bin", got, 0660); err != nil {
|
||||
if err := ioutil.WriteFile("junk.bin", bin, 0660); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
skipByte := map[int]bool{
|
||||
0x04ec: true, // line number of fake </uses-sdk> off by one
|
||||
0x0610: true, // line number of fake </meta-data> off by one
|
||||
0x064c: true, // line number of CData off by one
|
||||
0x06a0: true, // line number of fake </action> off by one
|
||||
0x06f0: true, // line number of fake </category> off by one
|
||||
0x0768: true, // line number of fake *end namespace* off by one
|
||||
if exec.Command("which", "aapt").Run() != nil {
|
||||
t.Skip("command aapt not found, skipping")
|
||||
}
|
||||
|
||||
for i, o := range output {
|
||||
if skipByte[i] {
|
||||
apiPath, err := androidAPIPath()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
androidJar := filepath.Join(apiPath, "android.jar")
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "gomobile-test-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
zw := zip.NewWriter(buf)
|
||||
zf, err := zw.Create("AndroidManifest.xml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := zf.Write(bin); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := zw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mblapk := filepath.Join(tmpdir, "mbl.apk")
|
||||
if err := ioutil.WriteFile(mblapk, buf.Bytes(), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, err := exec.Command("aapt", "d", "xmltree", mblapk, "AndroidManifest.xml").Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
manifest := filepath.Join(tmpdir, "AndroidManifest.xml")
|
||||
if err := ioutil.WriteFile(manifest, []byte(input), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sdkapk := filepath.Join(tmpdir, "sdk.apk")
|
||||
if _, err := exec.Command("aapt", "p", "-M", manifest, "-I", androidJar, "-F", sdkapk).Output(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sdkout, err := exec.Command("aapt", "d", "xmltree", sdkapk, "AndroidManifest.xml").Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// manifests contain platformBuildVersionCode and platformBuildVersionName
|
||||
// which are not present in gomobile output.
|
||||
var fo [][]byte
|
||||
for _, line := range bytes.Split(sdkout, []byte{'\n'}) {
|
||||
if bytes.Contains(line, []byte("platformBuildVersionCode")) || bytes.Contains(line, []byte("platformBuildVersionName")) {
|
||||
continue
|
||||
}
|
||||
if i >= len(got) || o != got[i] {
|
||||
t.Errorf("mismatch at %04x", i)
|
||||
break
|
||||
}
|
||||
fo = append(fo, line)
|
||||
}
|
||||
want := bytes.Join(fo, []byte{'\n'})
|
||||
|
||||
if !bytes.Equal(want, got) {
|
||||
t.Fatalf("output does not match\n\n%s\n\n%s\n", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +118,7 @@ func sortToMatchTest(p *binStringPool) {
|
|||
"hasCode",
|
||||
"debuggable",
|
||||
"name",
|
||||
"screenOrientation",
|
||||
"configChanges",
|
||||
"value",
|
||||
"android",
|
||||
|
@ -122,6 +177,7 @@ func sortAttrToMatchTest(e *binStartElement, p *binStringPool) {
|
|||
|
||||
"label",
|
||||
"name",
|
||||
"screenOrientation",
|
||||
"configChanges",
|
||||
}
|
||||
ordered := make([]*binAttr, len(order))
|
||||
|
@ -744,6 +800,7 @@ license that can be found in the LICENSE file.
|
|||
<application android:label="Balloon世界" android:hasCode="false" android:debuggable="true">
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
android:label="Balloon"
|
||||
android:screenOrientation="portrait"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<meta-data android:name="android.app.lib_name" android:value="balloon" />
|
||||
<intent-filter>
|
||||
|
|
Загрузка…
Ссылка в новой задаче