Merge "Continue refactoring of MediaFocusControl"
diff --git a/api/current.txt b/api/current.txt
index 2ba5e5c..97c1c74 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11578,6 +11578,7 @@
field public static final int FLASH_MODE_TORCH = 2; // 0x2
field public static final int FLASH_STATE_CHARGING = 1; // 0x1
field public static final int FLASH_STATE_FIRED = 3; // 0x3
+ field public static final int FLASH_STATE_PARTIAL = 4; // 0x4
field public static final int FLASH_STATE_READY = 2; // 0x2
field public static final int FLASH_STATE_UNAVAILABLE = 0; // 0x0
field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index c5fc941..1153f38 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -119,7 +119,8 @@
int parse_manifest(const void *data, size_t size, const char *target_package_name)
{
- ResXMLTree parser(data, size);
+ ResXMLTree parser;
+ parser.setTo(data, size);
if (parser.getError() != NO_ERROR) {
ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
return -1;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 69ada6a..965f815 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1592,10 +1592,10 @@
/**
* Creates the top level resources for the given package.
*/
- Resources getTopLevelResources(String resDir, String[] overlayDirs,
+ Resources getTopLevelResources(String resDir, String[] overlayDirs, String[] libDirs,
int displayId, Configuration overrideConfiguration,
LoadedApk pkgInfo) {
- return mResourcesManager.getTopLevelResources(resDir, overlayDirs, displayId,
+ return mResourcesManager.getTopLevelResources(resDir, overlayDirs, libDirs, displayId,
overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 8165fa1..0615bd9 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -805,7 +805,7 @@
}
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
- app.resourceDirs, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
+ app.resourceDirs, null, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
if (r != null) {
return r;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 87f47a1..589c82f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2044,8 +2044,9 @@
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
resources = mResourcesManager.getTopLevelResources(
- packageInfo.getResDir(), packageInfo.getOverlayDirs(), displayId,
- overrideConfiguration, compatInfo, activityToken);
+ packageInfo.getResDir(), packageInfo.getOverlayDirs(),
+ packageInfo.getApplicationInfo().sharedLibraryFiles,
+ displayId, overrideConfiguration, compatInfo, activityToken);
}
}
mResources = resources;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index d409352..3ae8bfc 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -41,6 +41,7 @@
import android.os.UserHandle;
import android.util.AndroidRuntimeException;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.DisplayAdjustments;
import android.view.Display;
@@ -48,6 +49,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Enumeration;
@@ -485,7 +488,7 @@
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs,
- Display.DEFAULT_DISPLAY, null, this);
+ mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
}
return mResources;
}
@@ -530,10 +533,101 @@
}
}
}
-
+
+ // Rewrite the R 'constants' for all library apks.
+ SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
+ .getAssignedPackageIdentifiers();
+ final int N = packageIdentifiers.size();
+ for (int i = 0; i < N; i++) {
+ final int id = packageIdentifiers.keyAt(i);
+ if (id == 0x01 || id == 0x7f) {
+ continue;
+ }
+
+ rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
+ }
+
return app;
}
+ private void rewriteIntField(Field field, int packageId) throws IllegalAccessException {
+ int requiredModifiers = Modifier.STATIC | Modifier.PUBLIC;
+ int bannedModifiers = Modifier.FINAL;
+
+ int mod = field.getModifiers();
+ if ((mod & requiredModifiers) != requiredModifiers ||
+ (mod & bannedModifiers) != 0) {
+ throw new IllegalArgumentException("Field " + field.getName() +
+ " is not rewritable");
+ }
+
+ if (field.getType() != int.class && field.getType() != Integer.class) {
+ throw new IllegalArgumentException("Field " + field.getName() +
+ " is not an integer");
+ }
+
+ try {
+ int resId = field.getInt(null);
+ field.setInt(null, (resId & 0x00ffffff) | (packageId << 24));
+ } catch (IllegalAccessException e) {
+ // This should not occur (we check above if we can write to it)
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private void rewriteIntArrayField(Field field, int packageId) {
+ int requiredModifiers = Modifier.STATIC | Modifier.PUBLIC;
+
+ if ((field.getModifiers() & requiredModifiers) != requiredModifiers) {
+ throw new IllegalArgumentException("Field " + field.getName() +
+ " is not rewritable");
+ }
+
+ if (field.getType() != int[].class) {
+ throw new IllegalArgumentException("Field " + field.getName() +
+ " is not an integer array");
+ }
+
+ try {
+ int[] array = (int[]) field.get(null);
+ for (int i = 0; i < array.length; i++) {
+ array[i] = (array[i] & 0x00ffffff) | (packageId << 24);
+ }
+ } catch (IllegalAccessException e) {
+ // This should not occur (we check above if we can write to it)
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private void rewriteRValues(ClassLoader cl, String packageName, int id) {
+ try {
+ final Class<?> rClazz = cl.loadClass(packageName + ".R");
+ Class<?>[] declaredClasses = rClazz.getDeclaredClasses();
+ for (Class<?> clazz : declaredClasses) {
+ try {
+ if (clazz.getSimpleName().equals("styleable")) {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.getType() == int[].class) {
+ rewriteIntArrayField(field, id);
+ }
+ }
+
+ } else {
+ for (Field field : clazz.getDeclaredFields()) {
+ rewriteIntField(field, id);
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to rewrite R values for " +
+ clazz.getName(), e);
+ }
+ }
+
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to rewrite R values", e);
+ }
+ }
+
public void removeContextRegistrations(Context context,
String who, String what) {
final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 728f372..a67faa0 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -144,14 +144,16 @@
* Creates the top level Resources for applications with the given compatibility info.
*
* @param resDir the resource directory.
+ * @param overlayDirs the resource overlay directories.
+ * @param libDirs the shared library resource dirs this app references.
* @param compatInfo the compability info. Must not be null.
* @param token the application token for determining stack bounds.
*/
- public Resources getTopLevelResources(String resDir, String[] overlayDirs, int displayId,
- Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
+ public Resources getTopLevelResources(String resDir, String[] overlayDirs, String[] libDirs,
+ int displayId, Configuration overrideConfiguration, CompatibilityInfo compatInfo,
+ IBinder token) {
final float scale = compatInfo.applicationScale;
- ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
- token);
+ ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);
Resources r;
synchronized (this) {
// Resources is app scale dependent.
@@ -186,6 +188,15 @@
}
}
+ if (libDirs != null) {
+ for (String libDir : libDirs) {
+ if (assets.addAssetPath(libDir) == 0) {
+ Slog.w(TAG, "Asset path '" + libDir +
+ "' does not exist or contains no resources.");
+ }
+ }
+ }
+
//Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics dm = getDisplayMetricsLocked(displayId);
Configuration config;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 2f8dd53..0c04401 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -18,6 +18,7 @@
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import android.util.SparseArray;
import android.util.TypedValue;
import java.io.FileNotFoundException;
@@ -266,11 +267,9 @@
}
}
- /*package*/ final CharSequence getPooledString(int block, int id) {
- //System.out.println("Get pooled: block=" + block
- // + ", id=#" + Integer.toHexString(id)
- // + ", blocks=" + mStringBlocks);
- return mStringBlocks[block-1].get(id);
+ /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
+ // Cookies map to string blocks starting at 1.
+ return mStringBlocks[cookie - 1].get(id);
}
/**
@@ -740,6 +739,11 @@
/**
* {@hide}
*/
+ public native final SparseArray<String> getAssignedPackageIdentifiers();
+
+ /**
+ * {@hide}
+ */
public native static final int getGlobalAssetCount();
/**
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index baf887e..d7199ff 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -834,7 +834,7 @@
}
return null;
}
- return mAssets.getPooledString(cookie, data[index+AssetManager.STYLE_DATA]);
+ return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
}
/*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index 3ad357f2..2f4d69b0 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -375,7 +375,7 @@
boolean defaultValue) {
int t = nativeGetAttributeDataType(mParseState, idx);
// Note: don't attempt to convert any other types, because
- // we want to count on appt doing the conversion for us.
+ // we want to count on aapt doing the conversion for us.
if (t >= TypedValue.TYPE_FIRST_INT &&
t <= TypedValue.TYPE_LAST_INT) {
return nativeGetAttributeData(mParseState, idx) != 0;
@@ -385,7 +385,7 @@
public int getAttributeResourceValue(int idx, int defaultValue) {
int t = nativeGetAttributeDataType(mParseState, idx);
// Note: don't attempt to convert any other types, because
- // we want to count on appt doing the conversion for us.
+ // we want to count on aapt doing the conversion for us.
if (t == TypedValue.TYPE_REFERENCE) {
return nativeGetAttributeData(mParseState, idx);
}
@@ -394,7 +394,7 @@
public int getAttributeIntValue(int idx, int defaultValue) {
int t = nativeGetAttributeDataType(mParseState, idx);
// Note: don't attempt to convert any other types, because
- // we want to count on appt doing the conversion for us.
+ // we want to count on aapt doing the conversion for us.
if (t >= TypedValue.TYPE_FIRST_INT &&
t <= TypedValue.TYPE_LAST_INT) {
return nativeGetAttributeData(mParseState, idx);
@@ -404,7 +404,7 @@
public int getAttributeUnsignedIntValue(int idx, int defaultValue) {
int t = nativeGetAttributeDataType(mParseState, idx);
// Note: don't attempt to convert any other types, because
- // we want to count on appt doing the conversion for us.
+ // we want to count on aapt doing the conversion for us.
if (t >= TypedValue.TYPE_FIRST_INT &&
t <= TypedValue.TYPE_LAST_INT) {
return nativeGetAttributeData(mParseState, idx);
@@ -414,7 +414,7 @@
public float getAttributeFloatValue(int idx, float defaultValue) {
int t = nativeGetAttributeDataType(mParseState, idx);
// Note: don't attempt to convert any other types, because
- // we want to count on appt doing the conversion for us.
+ // we want to count on aapt doing the conversion for us.
if (t == TypedValue.TYPE_FLOAT) {
return Float.intBitsToFloat(
nativeGetAttributeData(mParseState, idx));
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a3fbfbe..42c8e3da 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1625,38 +1625,37 @@
//
/**
- * <p>No flash on camera</p>
+ * <p>No flash on camera.</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_UNAVAILABLE = 0;
/**
- * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is
- * charging and cannot be fired</p>
- *
- * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+ * <p>Flash is charging and cannot be fired.</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_CHARGING = 1;
/**
- * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is
- * ready to fire</p>
- *
- * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+ * <p>Flash is ready to fire.</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_READY = 2;
/**
- * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash fired
- * for this capture</p>
- *
- * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+ * <p>Flash fired for this capture.</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_FIRED = 3;
+ /**
+ * <p>Flash partially illuminated this frame. This is usually due to the next
+ * or previous frame having the flash fire, and the flash spilling into this capture
+ * due to hardware limitations.</p>
+ * @see CaptureResult#FLASH_STATE
+ */
+ public static final int FLASH_STATE_PARTIAL = 4;
+
//
// Enumeration values for CaptureResult#LENS_STATE
//
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 9bf1b98..b3bce3b 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1164,6 +1164,7 @@
* @see #FLASH_STATE_CHARGING
* @see #FLASH_STATE_READY
* @see #FLASH_STATE_FIRED
+ * @see #FLASH_STATE_PARTIAL
*/
public static final Key<Integer> FLASH_STATE =
new Key<Integer>("android.flash.state", int.class);
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index 1e476fc..a28b5a7 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,22 +16,26 @@
package android.net.http;
-import com.android.org.conscrypt.SSLParametersImpl;
-import com.android.org.conscrypt.TrustManagerImpl;
+import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
-import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import javax.net.ssl.DefaultHostnameVerifier;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
/**
* Class responsible for all server certificate validation functionality
@@ -39,28 +43,51 @@
* {@hide}
*/
public class CertificateChainValidator {
+ private static final String TAG = "CertificateChainValidator";
- /**
- * The singleton instance of the certificate chain validator
- */
- private static final CertificateChainValidator sInstance
- = new CertificateChainValidator();
+ private static class NoPreloadHolder {
+ /**
+ * The singleton instance of the certificate chain validator.
+ */
+ private static final CertificateChainValidator sInstance = new CertificateChainValidator();
- private static final DefaultHostnameVerifier sVerifier
- = new DefaultHostnameVerifier();
+ /**
+ * The singleton instance of the hostname verifier.
+ */
+ private static final HostnameVerifier sVerifier = HttpsURLConnection
+ .getDefaultHostnameVerifier();
+ }
+
+ private X509ExtendedTrustManager mTrustManager;
/**
* @return The singleton instance of the certificates chain validator
*/
public static CertificateChainValidator getInstance() {
- return sInstance;
+ return NoPreloadHolder.sInstance;
}
/**
* Creates a new certificate chain validator. This is a private constructor.
* If you need a Certificate chain validator, call getInstance().
*/
- private CertificateChainValidator() {}
+ private CertificateChainValidator() {
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509ExtendedTrustManager) {
+ mTrustManager = (X509ExtendedTrustManager) tm;
+ }
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("X.509 TrustManager factory must be available", e);
+ }
+
+ if (mTrustManager == null) {
+ throw new RuntimeException(
+ "None of the X.509 TrustManagers are X509ExtendedTrustManager");
+ }
+ }
/**
* Performs the handshake and server certificates validation
@@ -136,14 +163,27 @@
* Handles updates to credential storage.
*/
public static void handleTrustStorageUpdate() {
-
+ TrustManagerFactory tmf;
try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
- if( x509TrustManager instanceof TrustManagerImpl ) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.handleTrustStorageUpdate();
+ tmf = TrustManagerFactory.getInstance("X.509");
+ } catch (NoSuchAlgorithmException e) {
+ Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
+ return;
+ }
+
+ TrustManager[] tms = tmf.getTrustManagers();
+ boolean sentUpdate = false;
+ for (TrustManager tm : tms) {
+ try {
+ Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
+ updateMethod.setAccessible(true);
+ updateMethod.invoke(tm);
+ sentUpdate = true;
+ } catch (Exception e) {
}
- } catch (KeyManagementException ignored) {
+ }
+ if (!sentUpdate) {
+ Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
}
}
@@ -166,7 +206,8 @@
boolean valid = domain != null
&& !domain.isEmpty()
- && sVerifier.verify(domain, currCertificate);
+ && NoPreloadHolder.sVerifier.verify(domain,
+ new DelegatingSSLSession.CertificateWrap(currCertificate));
if (!valid) {
if (HttpLog.LOGV) {
HttpLog.v("certificate not for this host: " + domain);
@@ -175,13 +216,8 @@
}
try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
- if (x509TrustManager instanceof TrustManagerImpl) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.checkServerTrusted(chain, authType, domain);
- } else {
- x509TrustManager.checkServerTrusted(chain, authType);
- }
+ getInstance().getTrustManager().checkServerTrusted(chain, authType,
+ new DelegatingSocketWrapper(domain));
return null; // No errors.
} catch (GeneralSecurityException e) {
if (HttpLog.LOGV) {
@@ -192,6 +228,12 @@
}
}
+ /**
+ * Returns the platform default {@link X509ExtendedTrustManager}.
+ */
+ private X509ExtendedTrustManager getTrustManager() {
+ return mTrustManager;
+ }
private void closeSocketThrowException(
SSLSocket socket, String errorMessage, String defaultErrorMessage)
@@ -217,4 +259,4 @@
throw new SSLHandshakeException(errorMessage);
}
-}
+}
\ No newline at end of file
diff --git a/core/java/android/net/http/DelegatingSSLSession.java b/core/java/android/net/http/DelegatingSSLSession.java
new file mode 100644
index 0000000..ff75b24
--- /dev/null
+++ b/core/java/android/net/http/DelegatingSSLSession.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ * This is used when only a {@code hostname} is available but usage of the new API
+ * {@link X509ExtendedTrustManager#checkServerTrusted(X509Certificate[], String, Socket)}
+ * requires a {@link SSLSocket}.
+ *
+ * @hide
+ */
+public class DelegatingSSLSession implements SSLSession {
+ protected DelegatingSSLSession() {
+ }
+
+ public static class HostnameWrap extends DelegatingSSLSession {
+ private final String mHostname;
+
+ public HostnameWrap(String hostname) {
+ mHostname = hostname;
+ }
+
+ @Override
+ public String getPeerHost() {
+ return mHostname;
+ }
+ }
+
+ public static class CertificateWrap extends DelegatingSSLSession {
+ private final Certificate mCertificate;
+
+ public CertificateWrap(Certificate certificate) {
+ mCertificate = certificate;
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ return new Certificate[] { mCertificate };
+ }
+ }
+
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPeerHost() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/net/http/DelegatingSocketWrapper.java b/core/java/android/net/http/DelegatingSocketWrapper.java
new file mode 100644
index 0000000..230d017
--- /dev/null
+++ b/core/java/android/net/http/DelegatingSocketWrapper.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import java.io.IOException;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ * This is used when only a {@code hostname} is available for
+ * {@link X509ExtendedTrustManager#checkServerTrusted(java.security.cert.X509Certificate[], String, Socket)}
+ * but we want to use the new API that requires a {@link SSLSocket}.
+ */
+class DelegatingSocketWrapper extends SSLSocket {
+ private String hostname;
+
+ public DelegatingSocketWrapper(String hostname) {
+ this.hostname = hostname;
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return new DelegatingSSLSession.HostnameWrap(hostname);
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startHandshake() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index db71279..a500bcf 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -22,14 +22,25 @@
import java.security.cert.X509Certificate;
import java.util.List;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
/**
* X509TrustManager wrapper exposing Android-added features.
- *
- * <p> The checkServerTrusted method allows callers to perform additional
- * verification of certificate chains after they have been successfully
- * verified by the platform.</p>
+ * <p>
+ * The checkServerTrusted method allows callers to perform additional
+ * verification of certificate chains after they have been successfully verified
+ * by the platform.
+ * </p>
+ * <p>
+ * If the returned certificate list is not needed, see also
+ * {@code X509ExtendedTrustManager#checkServerTrusted(X509Certificate[], String, java.net.Socket)}
+ * where an {@link SSLSocket} can be used to verify the given hostname during
+ * handshake using
+ * {@code SSLParameters#setEndpointIdentificationAlgorithm(String)}.
+ * </p>
*/
public class X509TrustManagerExtensions {
@@ -61,7 +72,8 @@
*/
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
String host) throws CertificateException {
- return mDelegate.checkServerTrusted(chain, authType, host);
+ return mDelegate.checkServerTrusted(chain, authType,
+ new DelegatingSSLSession.HostnameWrap(host));
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5e512b6..6ee99ec 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5726,7 +5726,8 @@
* @hide
*/
public int getAccessibilityWindowId() {
- return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId : NO_ID;
+ return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId
+ : AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
}
/**
@@ -19725,7 +19726,7 @@
/**
* The id of the window for accessibility purposes.
*/
- int mAccessibilityWindowId = View.NO_ID;
+ int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
/**
* Flags related to accessibility processing.
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 9dde701a..4147608 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -73,6 +73,13 @@
jfieldID mObject;
} gAssetManagerOffsets;
+static struct sparsearray_offsets_t
+{
+ jclass classObject;
+ jmethodID constructor;
+ jmethodID put;
+} gSparseArrayOffsets;
+
jclass g_stringClass = NULL;
// ----------------------------------------------------------------------------
@@ -905,6 +912,26 @@
return str;
}
+static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ const ResTable& res = am->getResources();
+
+ jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
+ gSparseArrayOffsets.constructor);
+ const size_t N = res.getBasePackageCount();
+ for (size_t i = 0; i < N; i++) {
+ const String16 name = res.getBasePackageName(i);
+ env->CallVoidMethod(sparseArray, gSparseArrayOffsets.put, (jint) res.getBasePackageId(i),
+ env->NewString(name, name.size()));
+ }
+ return sparseArray;
+}
+
static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
@@ -1675,16 +1702,19 @@
return 0;
}
- Asset* a = cookie
- ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_BUFFER)
- : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
+ int32_t assetCookie = static_cast<int32_t>(cookie);
+ Asset* a = assetCookie
+ ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+ : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
if (a == NULL) {
jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
return 0;
}
- ResXMLTree* block = new ResXMLTree();
+ const DynamicRefTable* dynamicRefTable =
+ am->getResources().getDynamicRefTableForCookie(assetCookie);
+ ResXMLTree* block = new ResXMLTree(dynamicRefTable);
status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
a->close();
delete a;
@@ -1972,6 +2002,8 @@
(void*) android_content_AssetManager_getNativeStringBlock },
{ "getCookieName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getCookieName },
+ { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
+ (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
// Themes.
{ "newTheme", "()J",
@@ -2068,6 +2100,16 @@
g_stringClass = (jclass)env->NewGlobalRef(stringClass);
LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
+ jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
+ LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
+ gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
+ gSparseArrayOffsets.constructor =
+ env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
+ LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
+ gSparseArrayOffsets.put =
+ env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
+ LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
+
return AndroidRuntime::registerNativeMethods(env,
"android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
}
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 03de5c0a..2cccb83 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -47,10 +47,11 @@
}
jbyte* b = env->GetByteArrayElements(bArray, NULL);
- ResXMLTree* osb = new ResXMLTree(b+off, len, true);
+ ResXMLTree* osb = new ResXMLTree();
+ osb->setTo(b+off, len, true);
env->ReleaseByteArrayElements(bArray, b, 0);
- if (osb == NULL || osb->getError() != NO_ERROR) {
+ if (osb->getError() != NO_ERROR) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return 0;
}
@@ -113,6 +114,8 @@
return 1;
case ResXMLParser::BAD_DOCUMENT:
goto bad;
+ default:
+ break;
}
} while (true);
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 7c0b7bc..f51b8df 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -23,7 +23,7 @@
<item name="windowSwipeToDismiss">true</item>
</style>
- <style name="Theme.Micro.NoActionBar" parent="Theme.Holo.NoActionBar">
+ <style name="Theme.Micro.Light" parent="Theme.Holo.Light.NoActionBar">
<item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
<item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
@@ -31,28 +31,4 @@
<item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
</style>
- <style name="Theme.Micro.Light" parent="Theme.Holo.Light">
- <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
- <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
- <item name="windowIsFloating">false</item>
- <item name="windowIsTranslucent">true</item>
- <item name="windowSwipeToDismiss">true</item>
- </style>
- <style name="Theme.Micro.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar">
- <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
- <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
- <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
- <item name="windowIsFloating">false</item>
- <item name="windowIsTranslucent">true</item>
- <item name="windowSwipeToDismiss">true</item>
- </style>
- <style name="Theme.Micro.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar">
- <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
- <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
- <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
- <item name="windowIsFloating">false</item>
- <item name="windowIsTranslucent">true</item>
- <item name="windowSwipeToDismiss">true</item>
- </style>
-
</resources>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 0d9a386..97c1b33 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -133,6 +133,8 @@
RobotoCondensed-Bold.ttf \
RobotoCondensed-Italic.ttf \
RobotoCondensed-BoldItalic.ttf \
+ RobotoCondensed-Light.ttf \
+ RobotoCondensed-LightItalic.ttf \
DroidNaskh-Regular.ttf \
DroidNaskhUI-Regular.ttf \
DroidSansHebrew-Regular.ttf \
diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf
new file mode 100644
index 0000000..41d212a
--- /dev/null
+++ b/data/fonts/RobotoCondensed-Light.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf
new file mode 100755
index 0000000..dd54971
--- /dev/null
+++ b/data/fonts/RobotoCondensed-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 05cca13e..293ecc8 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -32,6 +32,8 @@
RobotoCondensed-Bold.ttf \
RobotoCondensed-Italic.ttf \
RobotoCondensed-BoldItalic.ttf \
+ RobotoCondensed-Light.ttf \
+ RobotoCondensed-LightItalic.ttf \
DroidNaskh-Regular.ttf \
DroidNaskhUI-Regular.ttf \
DroidSansHebrew-Regular.ttf \
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
index 549f061b..a8d23ee 100644
--- a/data/fonts/system_fonts.xml
+++ b/data/fonts/system_fonts.xml
@@ -65,6 +65,17 @@
<file>RobotoCondensed-BoldItalic.ttf</file>
</fileset>
</family>
+
+ <family>
+ <nameset>
+ <name>sans-serif-condensed-light</name>
+ </nameset>
+ <fileset>
+ <file>RobotoCondensed-Light.ttf</file>
+ <file>RobotoCondensed-LightItalic.ttf</file>
+ </fileset>
+ </family>
+
<family>
<nameset>
<name>serif</name>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 8bb75df..e7f78e8 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -4,44 +4,45 @@
header.hide=1
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
+sdk.version=22.6.2
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20131030.zip
-sdk.linux32_bundle_bytes=496876498
-sdk.linux32_bundle_checksum=d389139ad9f59a43bdd34c94bc850509
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20140321.zip
+sdk.linux32_bundle_bytes=527971926
+sdk.linux32_bundle_checksum=943ae4d28fe7c79108c8bf2aafd5e6d2
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20131030.zip
-sdk.linux64_bundle_bytes=497171697
-sdk.linux64_bundle_checksum=99b51a4f0526434b083701a896550b72
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20140321.zip
+sdk.linux64_bundle_bytes=528187678
+sdk.linux64_bundle_checksum=f2a2153b5c7dbaeb86b550bf4f770c36
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20131030.zip
-sdk.mac64_bundle_bytes=470386961
-sdk.mac64_bundle_checksum=3e80e7a92b549029d91bdcf2ae82657f
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20140321.zip
+sdk.mac64_bundle_bytes=501955296
+sdk.mac64_bundle_checksum=4a08649cea9b098cdf7349f452294014
-sdk.win32_bundle_download=adt-bundle-windows-x86-20131030.zip
-sdk.win32_bundle_bytes=503599460
-sdk.win32_bundle_checksum=cd490a531ec24667354f6473e999b988
+sdk.win32_bundle_download=adt-bundle-windows-x86-20140321.zip
+sdk.win32_bundle_bytes=535085536
+sdk.win32_bundle_checksum=b61495a6bf591cc374c31bce4fc46ec0
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20131030.zip
-sdk.win64_bundle_bytes=503735416
-sdk.win64_bundle_checksum=ddddbb1b9028015779d68dde01f96b14
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20140321.zip
+sdk.win64_bundle_bytes=535287324
+sdk.win64_bundle_checksum=a6f4699bbdc5a29b371ed60610535651
-sdk.linux_download=android-sdk_r22.6.1-linux.tgz
-sdk.linux_bytes=101052129
-sdk.linux_checksum=d95b400600e9b68ed7719e0fd1792e0b
+sdk.linux_download=android-sdk_r22.6.2-linux.tgz
+sdk.linux_bytes=101050024
+sdk.linux_checksum=ff1541418a44d894bedc5cef10622220
-sdk.mac_download=android-sdk_r22.6.1-macosx.zip
-sdk.mac_bytes=74639176
-sdk.mac_checksum=99abc850398ccc220e3a1d6d0ab73ccf
+sdk.mac_download=android-sdk_r22.6.2-macosx.zip
+sdk.mac_bytes=74639394
+sdk.mac_checksum=2a319c862dd1dcf450bfe2a6b3d9c608
-sdk.win_download=android-sdk_r22.6.1-windows.zip
-sdk.win_bytes=108914728
-sdk.win_checksum=88471340a8c99822ffb5efbe3c28167c
+sdk.win_download=android-sdk_r22.6.2-windows.zip
+sdk.win_bytes=108917505
+sdk.win_checksum=6e5bfdb7b9c1d231ed6ec78b31551cbf
-sdk.win_installer=installer_r22.6.1-windows.exe
-sdk.win_installer_bytes=88907175
-sdk.win_installer_checksum=fd664527ed1b1b1bfe2d4546cafc7ada
+sdk.win_installer=installer_r22.6.2-windows.exe
+sdk.win_installer_bytes=87383126
+sdk.win_installer_checksum=2a68b8b22ecd0aba779b1581a914b395
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 42cb92c..1f5ca11 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
-adt.zip.version=22.6.0
-adt.zip.download=ADT-22.6.0.zip
-adt.zip.bytes=14585211
-adt.zip.checksum=d95c6d8e678881f6c89f063b58d4162f
+adt.zip.version=22.6.2
+adt.zip.download=ADT-22.6.2.zip
+adt.zip.bytes=14586842
+adt.zip.checksum=f660959fa71262b4285bcb64be284bf5
@jd:body
@@ -75,7 +75,7 @@
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>App Translations in Google Play</h2>
-<p>Google Play <a href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">App
+<p>Google Play <a href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">App
Translation Service</a> is available in the Developer Console to help you
localize your app for a global user base. You can browse qualified vendors, get
estimates, upload strings for translation, and then import the translations directly
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index feb7a6e..071492d 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -253,36 +253,36 @@
<td>Windows</td>
<td>
<a onclick="return onDownload(this)" id="win-studio"
- href="http://dl.google.com/android/studio/install/0.4.2/android-studio-bundle-133.970939-windows.exe">
- android-studio-bundle-133.970939-windows.exe
+ href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-windows.exe">
+ android-studio-bundle-133.1028713-windows.exe
</a>
</td>
- <td>515261701 bytes</td>
- <td>1e1ae28b1c00f43d55f17ee35bd4f5d2</td>
+ <td>519592042 bytes</td>
+ <td>9029c18738a75830786326d62c96d557</td>
</tr>
<tr>
<td><nobr>Mac OS X</nobr></td>
<td>
<a onclick="return onDownload(this)" id="mac-studio"
- href="http://dl.google.com/android/studio/install/0.4.2/android-studio-bundle-133.970939-mac.dmg">
- android-studio-bundle-133.970939-mac.dmg
+ href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-mac.dmg">
+ android-studio-bundle-133.1028713-mac.dmg
</a>
</td>
- <td>491773471 bytes</td>
- <td>6753f67c56acb17617bfbc5bc56384e7</td>
+ <td>497595811 bytes</td>
+ <td>eb2474e6d17537ddfa535e6fe8adcf0d</td>
</tr>
<tr>
<td>Linux</td>
<td>
<a onclick="return onDownload(this)" id="linux-studio"
- href="http://dl.google.com/android/studio/install/0.4.2/android-studio-bundle-133.970939-linux.tgz">
- android-studio-bundle-133.970939-linux.tgz
+ href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-linux.tgz">
+ android-studio-bundle-133.1028713-linux.tgz
</a>
</td>
- <td>516080363 bytes</td>
- <td>25455787d76e61baf34bf93eaa00ded6</td>
+ <td>522177460 bytes</td>
+ <td>cc847dd6249b3033737dabe0377c8c66</td>
</tr>
</table>
@@ -318,7 +318,7 @@
<h2 id="Installing">Installing Android Studio</h2>
-<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
+<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
If JDK is not available or the version is lower than 6,
<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">download
@@ -430,6 +430,19 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Android Studio v0.4.6</a> <em>(March 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+ <ul>
+ <li>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</li>
+ </ul>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Android Studio v0.4.2</a> <em>(Jan 2014)</em>
</p>
@@ -637,7 +650,7 @@
if (os) {
/* set up primary ACE download button */
$('#download-ide-button').show();
- $('#download-ide-button').append("Download Android Studio <span class='small'>v0.4.2</span>"
+ $('#download-ide-button').append("Download Android Studio <span class='small'>v0.4.6</span>"
+ "<br/> <span class='small'>for " + os + "</span>");
$('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index 99a271f..5d1d13b 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -93,6 +93,21 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 4</a> <em>(March 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <p>This release includes
+ <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 4.3,
+ allowing you to test your application in an emulator using the latest Google Play services.</p>
+
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png"
class="toggle-content-img" alt="" />Revision 3</a> <em>(February 2014)</em>
</p>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index a821757..7d20d5e 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,47 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 22.6.2</a> <em>(March 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.6.2</a>.
+ If you haven't already installed SDK Tools r22.6.2 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem where Eclipse was non-responsive for a few seconds after opening
+ an XML file. (<a href="http://b.android.com/67084">Issue 67084</a>)</li>
+ <li>Fixed a problem where the SDK Manager threw a <code>NullPointerException</code> after
+ removing a virtual device that was created using the Android Wear
+ system image. (<a href="http://b.android.com/67588">Issue 67588</a>)</li>
+ <li>Fixed a problem where the layout preview for large screens in Eclipse showed the
+ resources from the <code>drawable-*</code> directories instead of those from the
+ <code>drawable-large-*</code> directories.</li>
+ <li>Fixed a problem with Nexus 5 Android virtual devices created from the command line
+ where the SD card file system was read-only.</li>
+ <li>Changed the URL for the Android Developer Tools Update Site from HTTP to HTTPS.</li>
+ </ul>
+ </dd>
+</dl>
+</div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 22.6.1</a> <em>(March 2014)</em>
</p>
@@ -78,8 +119,8 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed a problem where the Android Virtual Device Manager could not create new virtual
- devices. (<a href="http://b.android.com/66661">Issue 66661</a>)</li>
+ <li>Fixed a problem where the Android Virtual Device Manager could not create new
+ virtual devices. (<a href="http://b.android.com/66661">Issue 66661</a>)</li>
<li><p>Fixed a problem with virtual devices created using ADT 22.3 or earlier.</p>
<p>If you created an Android Virtual Device using ADT 22.3 or earlier, the
AVD may be listed as <em>broken</em> in the AVD Manager in 22.6.1. To fix
@@ -102,7 +143,6 @@
</div>
</div>
-
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 675cde3..14b5505 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,41 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 22.6.2</a> <em>(March 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 18 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+ designed for use with ADT 22.6.2 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.6.2.</li>
+ <li>If you are developing outside Eclipse, you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem where the SDK Manager threw a <code>NullPointerException</code> after
+ removing a virtual device that was created using the Android Wear
+ system image. (<a href="http://b.android.com/67588">Issue 67588</a>)</li>
+ <li>Fixed a problem with Nexus 5 Android virtual devices created from the command line
+ where the SD card file system was read-only.</li>
+ </ul>
+ </dd>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 22.6.1</a> <em>(March 2014)</em>
</p>
@@ -124,7 +159,7 @@
</ul>
</li>
<li>Check that production builds do not use mock location providers.</li>
- <li>Look for manifest values that are overwritten by values from Gradle build
+ <li>Look for manifest values that are overwritten by values from Gradle build
scripts.</li>
</ul>
</li>
@@ -148,7 +183,7 @@
(<a href="http://b.android.com/34233">Issue 34233</a>)</li>
</ul>
</li>
- <li>Fixed an issue with RenderScript support. Using RenderScript support mode
+ <li>Fixed an issue with RenderScript support. Using RenderScript support mode
now requires version 19.0.3 of the Build Tools.</li>
</ul>
</dd>
diff --git a/docs/html/wear/images/screens/cuecard.gif b/docs/html/wear/images/screens/cuecard.gif
index 4b3d2f3..de1f53b 100644
--- a/docs/html/wear/images/screens/cuecard.gif
+++ b/docs/html/wear/images/screens/cuecard.gif
Binary files differ
diff --git a/docs/html/wear/images/screens/stream.gif b/docs/html/wear/images/screens/stream.gif
index 656a277..3c18775 100644
--- a/docs/html/wear/images/screens/stream.gif
+++ b/docs/html/wear/images/screens/stream.gif
Binary files differ
diff --git a/docs/html/wear/index.html b/docs/html/wear/index.html
index 712e1af..9660463 100644
--- a/docs/html/wear/index.html
+++ b/docs/html/wear/index.html
@@ -94,7 +94,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
+<meta name="viewport" content="width=970" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<title>Android Wear | Android Developers</title>
@@ -297,8 +297,8 @@
</div>
<script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<div id="ytapiplayer">
- <a href="http://www.youtube.com/watch?v=i2uvYI6blEE"><img width=600
- src="https://i1.ytimg.com/vi/i2uvYI6blEE/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+ <a href="http://www.youtube.com/watch?v=0xQ3y902DEQ"><img width=940
+ src="https://i1.ytimg.com/vi/0xQ3y902DEQ/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
</div>
</div>
</div>
@@ -346,9 +346,14 @@
});
$("#icon-video-close").on("click", function() {
ytplayer = document.getElementById("ytapiplayer");
- ytplayer.stopVideo();
- $(ytplayer).hide();
- $("#video-container").fadeOut(400);
+ try {
+ ytplayer.stopVideo();
+ $(ytplayer).hide();
+ $("#video-container").fadeOut(400);
+ } catch(e) {
+ console.log('Video not available');
+ $("#video-container").fadeOut(400);
+ }
});
</script>
</div>
@@ -650,7 +655,7 @@
<div class="g-plusone" data-size="medium"></div>
</div>
</div>
- <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px">
+ <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
<div id="copyright">
Except as noted, this content is
licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
diff --git a/docs/html/wear/notifications/creating.html b/docs/html/wear/notifications/creating.html
index e83b57a..7ad6833 100644
--- a/docs/html/wear/notifications/creating.html
+++ b/docs/html/wear/notifications/creating.html
@@ -572,9 +572,9 @@
<p>To use these new APIs, pass your instance of
<code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html">NotificationCompat.Builder</a></code> to the
- <a href="/reference/android/preview/support/notifications/WearableNotifications.html"> <code>WearableNotifications.Builder()</code></a> constructor. You can then add new
+ <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#WearableNotifications.Builder(android.content.Context)"> <code>WearableNotifications.Builder()</code></a> constructor. You can then add new
features to your notification using the
- <a href="/wear/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
+ <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
><code>WearableNotifications.Builder</code></a> methods. For example:</p>
<pre>
@@ -592,10 +592,10 @@
.build();
</pre>
-<p>The <a href="/reference/android/preview/support/notifications/WearableNotifications.Builder.html#setBigActionIcon(int)">
+<p>The <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setBigActionIcon(int)">
<code>setHintHideIcon()</code></a> method removes your app icon from the notification card.
This method is just one example of new notification features available from the
- <a href="/wear/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
+ <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
><code>WearableNotifications.Builder</code></a> class.</p>
<p>When you want to deliver your notifications, be certain to always use the
@@ -616,7 +616,7 @@
will not work.</p>
<p>To continue enhancing your notifications for wearables using
- <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder"
+ <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
><code>WearableNotifications.Builder</code></a> and other APIs in the
preview support library, see the following developer guides:</p>
diff --git a/docs/html/wear/preview/start.html b/docs/html/wear/preview/start.html
index 4aec648..b1861f5 100644
--- a/docs/html/wear/preview/start.html
+++ b/docs/html/wear/preview/start.html
@@ -558,7 +558,10 @@
The emulator should show the time and an icon that indicates no device is connected.</li>
<li>Open a command line terminal, navigate to your Android SDK's <code>platform-tools/</code>
directory, then execute:
-<pre style="margin-top:.5em">adb -d forward tcp:5601 tcp:5601</pre></li>
+<pre style="margin-top:.5em">adb -d forward tcp:5601 tcp:5601</pre>
+<p class="note"><strong>Note:</strong> You must execute this command each time you connect your
+device over USB.</p>
+</li>
<li>Return to the Android Wear Preview app. It should now indicate that it is connected to
the emulator. The Android Wear emulator should now show the 'g' orb icon, indicating
that is is connected to your device.
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index a13dd16..610528c 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -161,7 +161,7 @@
* path hierarchy, and will not be seen by "AssetDir" or included
* in our filename cache.
*/
- Asset* openNonAsset(const char* fileName, AccessMode mode);
+ Asset* openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie = NULL);
/*
* Explicit non-asset file. The file explicitly named by the cookie (the
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index b334aab..7cc10be87 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -25,6 +25,7 @@
#include <utils/Errors.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
#include <utils/threads.h>
@@ -216,7 +217,8 @@
// Chunk types in RES_TABLE_TYPE
RES_TABLE_PACKAGE_TYPE = 0x0200,
RES_TABLE_TYPE_TYPE = 0x0201,
- RES_TABLE_TYPE_SPEC_TYPE = 0x0202
+ RES_TABLE_TYPE_SPEC_TYPE = 0x0202,
+ RES_TABLE_LIBRARY_TYPE = 0x0203
};
/**
@@ -268,6 +270,9 @@
// The 'data' holds a complex number encoding a fraction of a
// container.
TYPE_FRACTION = 0x06,
+ // The 'data' holds a dynamic ResTable_ref, which needs to be
+ // resolved before it can be used like a TYPE_REFERENCE.
+ TYPE_DYNAMIC_REFERENCE = 0x07,
// Beginning of integer flavors...
TYPE_FIRST_INT = 0x10,
@@ -457,6 +462,7 @@
ResStringPool(const void* data, size_t size, bool copyData=false);
~ResStringPool();
+ void setToEmpty();
status_t setTo(const void* data, size_t size, bool copyData=false);
status_t getError() const;
@@ -735,14 +741,16 @@
const void* mCurExt;
};
+class DynamicRefTable;
+
/**
* Convenience class for accessing data in a ResXMLTree resource.
*/
class ResXMLTree : public ResXMLParser
{
public:
+ ResXMLTree(const DynamicRefTable* dynamicRefTable);
ResXMLTree();
- ResXMLTree(const void* data, size_t size, bool copyData=false);
~ResXMLTree();
status_t setTo(const void* data, size_t size, bool copyData=false);
@@ -756,6 +764,8 @@
status_t validateNode(const ResXMLTree_node* node) const;
+ const DynamicRefTable* const mDynamicRefTable;
+
status_t mError;
void* mOwnedData;
const ResXMLTree_header* mHeader;
@@ -1290,6 +1300,7 @@
struct ResTable_map_entry : public ResTable_entry
{
// Resource identifier of the parent mapping, or 0 if there is none.
+ // This is always treated as a TYPE_DYNAMIC_REFERENCE.
ResTable_ref parent;
// Number of name/value pairs that follow for FLAG_COMPLEX.
uint32_t count;
@@ -1385,6 +1396,68 @@
};
/**
+ * A package-id to package name mapping for any shared libraries used
+ * in this resource table. The package-id's encoded in this resource
+ * table may be different than the id's assigned at runtime. We must
+ * be able to translate the package-id's based on the package name.
+ */
+struct ResTable_lib_header
+{
+ struct ResChunk_header header;
+
+ // The number of shared libraries linked in this resource table.
+ uint32_t count;
+};
+
+/**
+ * A shared library package-id to package name entry.
+ */
+struct ResTable_lib_entry
+{
+ // The package-id this shared library was assigned at build time.
+ // We use a uint32 to keep the structure aligned on a uint32 boundary.
+ uint32_t packageId;
+
+ // The package name of the shared library. \0 terminated.
+ char16_t packageName[128];
+};
+
+/**
+ * Holds the shared library ID table. Shared libraries are assigned package IDs at
+ * build time, but they may be loaded in a different order, so we need to maintain
+ * a mapping of build-time package ID to run-time assigned package ID.
+ *
+ * Dynamic references are not currently supported in overlays. Only the base package
+ * may have dynamic references.
+ */
+class DynamicRefTable
+{
+public:
+ DynamicRefTable(uint8_t packageId);
+
+ // Loads an unmapped reference table from the package.
+ status_t load(const ResTable_lib_header* const header);
+
+ // Creates a mapping from build-time package ID to run-time package ID for
+ // the given package.
+ status_t addMapping(const String16& packageName, uint8_t packageId);
+
+ // Performs the actual conversion of build-time resource ID to run-time
+ // resource ID.
+ inline status_t lookupResourceId(uint32_t* resId) const;
+ inline status_t lookupResourceValue(Res_value* value) const;
+
+ inline const KeyedVector<String16, uint8_t>& entries() const {
+ return mEntries;
+ }
+
+private:
+ const uint8_t mAssignedPackageId;
+ uint8_t mLookupTable[256];
+ KeyedVector<String16, uint8_t> mEntries;
+};
+
+/**
* Convenience class for accessing data in a ResTable resource.
*/
class ResTable
@@ -1399,6 +1472,7 @@
const void* idmap = NULL);
status_t add(const void *data, size_t size);
status_t add(ResTable* src);
+ status_t addEmpty(const int32_t cookie);
status_t getError() const;
@@ -1634,7 +1708,7 @@
bool append = false);
size_t getBasePackageCount() const;
- const char16_t* getBasePackageName(size_t idx) const;
+ const String16 getBasePackageName(size_t idx) const;
uint32_t getBasePackageId(size_t idx) const;
// Return the number of resource tables that the object contains.
@@ -1647,6 +1721,8 @@
// Return unique cookie identifier for the given resource table.
int32_t getTableCookie(size_t index) const;
+ const DynamicRefTable* getDynamicRefTableForCookie(int32_t cookie) const;
+
// Return the configurations (ResTable_config) that we know about
void getConfigurations(Vector<ResTable_config>* configs) const;
@@ -1684,7 +1760,7 @@
struct bag_set;
status_t addInternal(const void* data, size_t size, const int32_t cookie,
- Asset* asset, bool copyData, const Asset* idmap);
+ bool copyData, const Asset* idmap);
ssize_t getResourcePackageIndex(uint32_t resID) const;
ssize_t getEntry(
@@ -1712,6 +1788,8 @@
// Mapping from resource package IDs to indices into the internal
// package array.
uint8_t mPackageMap[256];
+
+ uint8_t mNextPackageId;
};
} // namespace android
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 64363d4..91dda75 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -74,6 +74,7 @@
static const char* kAppZipName = NULL; //"classes.jar";
static const char* kSystemAssets = "framework/framework-res.apk";
static const char* kResourceCache = "resource-cache";
+static const char* kAndroidManifest = "AndroidManifest.xml";
static const char* kExcludeExtension = ".EXCLUDE";
@@ -205,6 +206,16 @@
ALOGV("In %p Asset %s path: %s", this,
ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
+ // Check that the path has an AndroidManifest.xml
+ Asset* manifestAsset = const_cast<AssetManager*>(this)->openNonAssetInPathLocked(
+ kAndroidManifest, Asset::ACCESS_BUFFER, ap);
+ if (manifestAsset == NULL) {
+ // This asset path does not contain any resources.
+ delete manifestAsset;
+ return false;
+ }
+ delete manifestAsset;
+
mAssetPaths.add(ap);
// new paths are always added at the end
@@ -461,7 +472,7 @@
* The "fileName" is the partial path starting from the application
* name.
*/
-Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode)
+Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie)
{
AutoMutex _l(mLock);
@@ -482,6 +493,7 @@
Asset* pAsset = openNonAssetInPathLocked(
fileName, mode, mAssetPaths.itemAt(i));
if (pAsset != NULL) {
+ if (outCookie != NULL) *outCookie = static_cast<int32_t>(i + 1);
return pAsset != kExcludedAsset ? pAsset : NULL;
}
}
@@ -556,9 +568,14 @@
LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
}
- if (mCacheMode != CACHE_OFF && !mCacheValid)
+ if (mCacheMode != CACHE_OFF && !mCacheValid) {
const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
+ }
+ mResources = new ResTable();
+ updateResourceParamsLocked();
+
+ bool onlyEmptyResources = true;
const size_t N = mAssetPaths.size();
for (size_t i=0; i<N; i++) {
Asset* ass = NULL;
@@ -621,35 +638,39 @@
ap);
shared = false;
}
+
if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
- if (rt == NULL) {
- mResources = rt = new ResTable();
- updateResourceParamsLocked();
- }
ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
if (sharedRes != NULL) {
ALOGV("Copying existing resources for %s", ap.path.string());
- rt->add(sharedRes);
+ mResources->add(sharedRes);
} else {
ALOGV("Parsing resources for %s", ap.path.string());
- rt->add(ass, i + 1, !shared, idmap);
+ mResources->add(ass, i + 1, !shared, idmap);
}
+ onlyEmptyResources = false;
if (!shared) {
delete ass;
}
+ } else {
+ ALOGW("Installing empty resources in to table %p\n", mResources);
+ mResources->addEmpty(i + 1);
}
+
if (idmap != NULL) {
delete idmap;
}
MY_TRACE_END();
}
- if (required && !rt) ALOGW("Unable to find resources file resources.arsc");
- if (!rt) {
- mResources = rt = new ResTable();
+ if (required && onlyEmptyResources) {
+ ALOGW("Unable to find resources file resources.arsc");
+ delete mResources;
+ mResources = NULL;
}
- return rt;
+
+ return mResources;
}
void AssetManager::updateResourceParamsLocked() const
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 652cd4a..04ca81e 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -42,6 +42,7 @@
#define TABLE_SUPER_NOISY(x) //x
#define LOAD_TABLE_NOISY(x) //x
#define TABLE_THEME(x) //x
+#define LIB_NOISY(x) x
namespace android {
@@ -66,6 +67,9 @@
// size measured in sizeof(uint32_t)
#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
+#define APP_PACKAGE_ID 0x7f
+#define SYS_PACKAGE_ID 0x01
+
// Standard C isspace() is only required to look at the low byte of its input, so
// produces incorrect results for UTF-16 characters. For safety's sake, assume that
// any high-byte UTF-16 code point is not whitespace.
@@ -113,7 +117,7 @@
name, size, headerSize);
return BAD_TYPE;
}
- ALOGW("%s header size 0x%x is too small.",
+ ALOGW("%s header size 0x%04x is too small.",
name, headerSize);
return BAD_TYPE;
}
@@ -264,7 +268,7 @@
}
const uint32_t index = typeOffset + 2 + entry - entryOffset;
if (index > size) {
- ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, (int)size);
+ ALOGW("Resource ID map: entry index=%u exceeds size of map=%d\n", index, (int)size);
*outValue = 0;
return NO_ERROR;
}
@@ -279,7 +283,7 @@
return UNKNOWN_ERROR;
}
if (mapSize <= IDMAP_HEADER_SIZE + 1) {
- ALOGW("corrupt idmap: map size %d too short\n", mapSize);
+ ALOGW("corrupt idmap: map size %d too short\n", (int)mapSize);
return UNKNOWN_ERROR;
}
uint32_t typeCount = *(map + IDMAP_HEADER_SIZE);
@@ -288,7 +292,7 @@
return UNKNOWN_ERROR;
}
if (IDMAP_HEADER_SIZE + 1 + typeCount > mapSize) {
- ALOGW("corrupt idmap: number of types %d extends past idmap size %d\n", typeCount, mapSize);
+ ALOGW("corrupt idmap: number of types %u extends past idmap size %d\n", typeCount, (int)mapSize);
return UNKNOWN_ERROR;
}
const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
@@ -304,7 +308,7 @@
// determine package id from first entry of first type
const uint32_t offset = *p + IDMAP_HEADER_SIZE + 2;
if (offset > mapSize) {
- ALOGW("corrupt idmap: entry offset %d points outside map size %d\n", offset, mapSize);
+ ALOGW("corrupt idmap: entry offset %u points outside map size %d\n", offset, (int)mapSize);
return UNKNOWN_ERROR;
}
*outId = (map[offset] >> 24) & 0x000000ff;
@@ -342,6 +346,22 @@
uninit();
}
+void ResStringPool::setToEmpty()
+{
+ uninit();
+
+ mOwnedData = calloc(1, sizeof(ResStringPool_header));
+ ResStringPool_header* header = (ResStringPool_header*) mOwnedData;
+ mSize = 0;
+ mEntries = NULL;
+ mStrings = NULL;
+ mStringPoolSize = 0;
+ mEntryStyles = NULL;
+ mStyles = NULL;
+ mStylePoolSize = 0;
+ mHeader = (const ResStringPool_header*) header;
+}
+
status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
{
if (!data || !size) {
@@ -1111,7 +1131,14 @@
(((const uint8_t*)tag)
+ dtohs(tag->attributeStart)
+ (dtohs(tag->attributeSize)*idx));
- return attr->typedValue.dataType;
+ uint8_t type = attr->typedValue.dataType;
+ if (type != Res_value::TYPE_DYNAMIC_REFERENCE) {
+ return type;
+ }
+
+ // This is a dynamic reference. We adjust those references
+ // to regular references at this level, so lie to the caller.
+ return Res_value::TYPE_REFERENCE;
}
}
return Res_value::TYPE_NULL;
@@ -1126,7 +1153,15 @@
(((const uint8_t*)tag)
+ dtohs(tag->attributeStart)
+ (dtohs(tag->attributeSize)*idx));
- return dtohl(attr->typedValue.data);
+ if (attr->typedValue.dataType != Res_value::TYPE_DYNAMIC_REFERENCE ||
+ mTree.mDynamicRefTable == NULL) {
+ return dtohl(attr->typedValue.data);
+ }
+
+ uint32_t data = dtohl(attr->typedValue.data);
+ if (mTree.mDynamicRefTable->lookupResourceId(&data) == NO_ERROR) {
+ return data;
+ }
}
}
return 0;
@@ -1142,6 +1177,10 @@
+ dtohs(tag->attributeStart)
+ (dtohs(tag->attributeSize)*idx));
outValue->copyFrom_dtoh(attr->typedValue);
+ if (mTree.mDynamicRefTable != NULL &&
+ mTree.mDynamicRefTable->lookupResourceValue(outValue) != NO_ERROR) {
+ return BAD_TYPE;
+ }
return sizeof(Res_value);
}
}
@@ -1333,25 +1372,26 @@
mCurExt = pos.curExt;
}
-
// --------------------------------------------------------------------
static volatile int32_t gCount = 0;
-ResXMLTree::ResXMLTree()
+ResXMLTree::ResXMLTree(const DynamicRefTable* dynamicRefTable)
: ResXMLParser(*this)
+ , mDynamicRefTable(dynamicRefTable)
, mError(NO_INIT), mOwnedData(NULL)
{
//ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
restart();
}
-ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData)
+ResXMLTree::ResXMLTree()
: ResXMLParser(*this)
+ , mDynamicRefTable(NULL)
, mError(NO_INIT), mOwnedData(NULL)
{
//ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
- setTo(data, size, copyData);
+ restart();
}
ResXMLTree::~ResXMLTree()
@@ -2737,7 +2777,14 @@
struct ResTable::PackageGroup
{
PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
- : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
+ : owner(_owner)
+ , name(_name)
+ , id(_id)
+ , typeCount(0)
+ , bags(NULL)
+ , dynamicRefTable(static_cast<uint8_t>(_id))
+ { }
+
~PackageGroup() {
clearBagCache();
const size_t N = packages.size();
@@ -2790,6 +2837,13 @@
// Computed attribute bags, first indexed by the type and second
// by the entry in that type.
bag_set*** bags;
+
+ // The table mapping dynamic references to resolved references for
+ // this package group.
+ // TODO: We may be able to support dynamic references in overlays
+ // by having these tables in a per-package scope rather than
+ // per-package-group.
+ DynamicRefTable dynamicRefTable;
};
struct ResTable::bag_set
@@ -3077,7 +3131,7 @@
}
ResTable::ResTable()
- : mError(NO_INIT)
+ : mError(NO_INIT), mNextPackageId(2)
{
memset(&mParams, 0, sizeof(mParams));
memset(mPackageMap, 0, sizeof(mPackageMap));
@@ -3085,11 +3139,11 @@
}
ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
- : mError(NO_INIT)
+ : mError(NO_INIT), mNextPackageId(2)
{
memset(&mParams, 0, sizeof(mParams));
memset(mPackageMap, 0, sizeof(mPackageMap));
- addInternal(data, size, cookie, NULL /* asset */, copyData, NULL /* idMap */);
+ addInternal(data, size, cookie, copyData, NULL /* idMap */);
LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
//ALOGI("Creating ResTable %p\n", this);
}
@@ -3106,7 +3160,7 @@
}
status_t ResTable::add(const void* data, size_t size) {
- return addInternal(data, size, 0 /* cookie */, NULL /* asset */,
+ return addInternal(data, size, 0 /* cookie */,
false /* copyData */, NULL /* idMap */);
}
@@ -3118,7 +3172,7 @@
return UNKNOWN_ERROR;
}
size_t size = (size_t)asset->getLength();
- return addInternal(data, size, cookie, asset, copyData,
+ return addInternal(data, size, cookie, copyData,
reinterpret_cast<const Asset*>(idmap));
}
@@ -3146,8 +3200,25 @@
return mError;
}
+status_t ResTable::addEmpty(const int32_t cookie) {
+ Header* header = new Header(this);
+ header->index = mHeaders.size();
+ header->cookie = cookie;
+ header->values.setToEmpty();
+ header->ownedData = calloc(1, sizeof(ResTable_header));
+
+ ResTable_header* resHeader = (ResTable_header*) header->ownedData;
+ resHeader->header.type = RES_TABLE_TYPE;
+ resHeader->header.headerSize = sizeof(ResTable_header);
+ resHeader->header.size = sizeof(ResTable_header);
+
+ header->header = (const ResTable_header*) resHeader;
+ mHeaders.add(header);
+ return NO_ERROR;
+}
+
status_t ResTable::addInternal(const void* data, size_t size, const int32_t cookie,
- Asset* /*asset*/, bool copyData, const Asset* idmap)
+ bool copyData, const Asset* idmap)
{
if (!data) return NO_ERROR;
Header* header = new Header(this);
@@ -3186,8 +3257,6 @@
//ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
// dtohl(header->header->header.size), header->header->header.size);
LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header));
- LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256,
- 16, 16, 0, false, printToLogFunc));
if (dtohs(header->header->header.headerSize) > header->size
|| header->size > size) {
ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
@@ -3474,9 +3543,6 @@
continue;
}
- TABLE_NOISY(aout << "Resource type data: "
- << HexDump(type, dtohl(type->header.size)) << endl);
-
if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
ALOGW("ResTable_item at %d is beyond type chunk data %d",
(int)offset, dtohl(type->header.size));
@@ -3516,6 +3582,18 @@
outValue->res0 = bestValue->res0;
outValue->dataType = bestValue->dataType;
outValue->data = dtohl(bestValue->data);
+
+ // The reference may be pointing to a resource in a shared library. These
+ // references have build-time generated package IDs. These ids may not match
+ // the actual package IDs of the corresponding packages in this ResTable.
+ // We need to fix the package ID based on a mapping.
+ status_t err = grp->dynamicRefTable.lookupResourceValue(outValue);
+ if (err != NO_ERROR) {
+ ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data);
+ rc = BAD_VALUE;
+ goto out;
+ }
+
if (outConfig != NULL) {
*outConfig = bestItem;
}
@@ -3545,8 +3623,8 @@
ResTable_config* outConfig) const
{
int count=0;
- while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
- && value->data != 0 && count < 20) {
+ while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE
+ && value->data != 0 && count < 20) {
if (outLastRef) *outLastRef = value->data;
uint32_t lastRef = value->data;
uint32_t newFlags = 0;
@@ -3730,7 +3808,7 @@
const Type* typeClass;
ALOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
- ALOGV("Resulting offset=%d\n", offset);
+ ALOGV("Resulting offset=%d\n", (int)offset);
if (offset <= 0) {
// No {entry, appropriate config} pair found in package. If this
// package is an overlay package (ip != 0), this simply means the
@@ -3774,9 +3852,21 @@
TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
entrySize, parent));
if (parent) {
+ uint32_t resolvedParent = parent;
+
+ // Bags encode a parent reference without using the standard
+ // Res_value structure. That means we must always try to
+ // resolve a parent reference in case it is actually a
+ // TYPE_DYNAMIC_REFERENCE.
+ status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent);
+ if (err != NO_ERROR) {
+ ALOGE("Failed resolving bag parent id 0x%08x", parent);
+ return UNKNOWN_ERROR;
+ }
+
const bag_entry* parentBag;
uint32_t parentTypeSpecFlags = 0;
- const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+ const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
const size_t NT = ((NP >= 0) ? NP : 0) + N;
set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
if (set == NULL) {
@@ -3871,6 +3961,12 @@
cur->stringBlock = package->header->index;
cur->map.name.ident = newName;
cur->map.value.copyFrom_dtoh(map->value);
+ status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value);
+ if (err != NO_ERROR) {
+ ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data);
+ return UNKNOWN_ERROR;
+ }
+
TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
curEntry, cur, cur->stringBlock, cur->map.name.ident,
cur->map.value.dataType, cur->map.value.data));
@@ -4568,16 +4664,20 @@
return false;
}
}
- if (!accessor) {
- outValue->data = rid;
- return true;
+
+ if (accessor) {
+ rid = Res_MAKEID(
+ accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
+ Res_GETTYPE(rid), Res_GETENTRY(rid));
+ TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
+ String8(package).string(), String8(type).string(),
+ String8(name).string(), rid));
}
- rid = Res_MAKEID(
- accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
- Res_GETTYPE(rid), Res_GETENTRY(rid));
- TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
- String8(package).string(), String8(type).string(),
- String8(name).string(), rid));
+
+ uint32_t packageId = Res_GETPACKAGE(rid) + 1;
+ if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
+ outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
+ }
outValue->data = rid;
return true;
}
@@ -4589,8 +4689,17 @@
TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
String8(package).string(), String8(type).string(),
String8(name).string(), rid));
- outValue->data = rid;
- return true;
+ uint32_t packageId = Res_GETPACKAGE(rid) + 1;
+ if (packageId == 0x00) {
+ outValue->data = rid;
+ outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
+ return true;
+ } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
+ // We accept packageId's generated as 0x01 in order to support
+ // building the android system resources
+ outValue->data = rid;
+ return true;
+ }
}
}
}
@@ -5122,15 +5231,15 @@
return mPackageGroups.size();
}
-const char16_t* ResTable::getBasePackageName(size_t idx) const
+const String16 ResTable::getBasePackageName(size_t idx) const
{
if (mError != NO_ERROR) {
- return 0;
+ return String16();
}
LOG_FATAL_IF(idx >= mPackageGroups.size(),
"Requested package index %d past package count %d",
(int)idx, (int)mPackageGroups.size());
- return mPackageGroups[idx]->name.string();
+ return mPackageGroups[idx]->name;
}
uint32_t ResTable::getBasePackageId(size_t idx) const
@@ -5159,6 +5268,21 @@
return mHeaders[index]->cookie;
}
+const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) const
+{
+ const size_t N = mPackageGroups.size();
+ for (size_t i = 0; i < N; i++) {
+ const PackageGroup* pg = mPackageGroups[i];
+ size_t M = pg->packages.size();
+ for (size_t j = 0; j < M; j++) {
+ if (pg->packages[j]->header->cookie == cookie) {
+ return &pg->dynamicRefTable;
+ }
+ }
+ }
+ return NULL;
+}
+
void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
{
const size_t I = mPackageGroups.size();
@@ -5300,10 +5424,9 @@
}
offset += dtohl(type->entriesStart);
- TABLE_NOISY(aout << "Looking in resource table " << package->header->header
- << ", typeOff="
- << (void*)(((const char*)type)-((const char*)package->header->header))
- << ", offset=" << (void*)offset << endl);
+ TABLE_NOISY(ALOGD("Looking in resource table %p, typeOff=%p, offset=%p",
+ package->header->header, (void*)(((const char*)type)-((const char*)package->header->header)),
+ (void*)offset));
if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
@@ -5377,6 +5500,11 @@
if (package == NULL) {
return (mError=NO_MEMORY);
}
+
+ if (id == 0) {
+ // This is a library so assign an ID
+ id = mNextPackageId++;
+ }
size_t idx = mPackageMap[id];
if (idx == 0) {
@@ -5413,6 +5541,13 @@
group->basePackage = package;
mPackageMap[id] = (uint8_t)idx;
+
+ // Find all packages that reference this package
+ size_t N = mPackageGroups.size();
+ for (size_t i = 0; i < N; i++) {
+ mPackageGroups[i]->dynamicRefTable.addMapping(
+ group->name, static_cast<uint8_t>(group->id));
+ }
} else {
group = mPackageGroups.itemAt(idx-1);
if (group == NULL) {
@@ -5457,7 +5592,7 @@
(void*)(base-(const uint8_t*)chunk),
dtohs(typeSpec->header.type),
dtohs(typeSpec->header.headerSize),
- (void*)typeSize));
+ (void*)typeSpecSize));
// look for block overrun or int overflow when multiplying by 4
if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
|| dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
@@ -5543,6 +5678,21 @@
ALOGI("Adding config to type %d: %s\n",
type->id, thisConfig.toString().string()));
t->configs.add(type);
+ } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
+ if (group->dynamicRefTable.entries().size() == 0) {
+ status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk);
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+
+ // Fill in the reference table with the entries we already know about.
+ size_t N = mPackageGroups.size();
+ for (size_t i = 0; i < N; i++) {
+ group->dynamicRefTable.addMapping(mPackageGroups[i]->name, mPackageGroups[i]->id);
+ }
+ } else {
+ ALOGW("Found multiple library tables, ignoring...");
+ }
} else {
status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
endPos, "ResTable_package:unknown");
@@ -5561,6 +5711,103 @@
return NO_ERROR;
}
+DynamicRefTable::DynamicRefTable(uint8_t packageId)
+ : mAssignedPackageId(packageId)
+{
+ memset(mLookupTable, 0, sizeof(mLookupTable));
+
+ // Reserved package ids
+ mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
+ mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
+}
+
+status_t DynamicRefTable::load(const ResTable_lib_header* const header)
+{
+ const uint32_t entryCount = dtohl(header->count);
+ const uint32_t sizeOfEntries = sizeof(ResTable_lib_entry) * entryCount;
+ const uint32_t expectedSize = dtohl(header->header.size) - dtohl(header->header.headerSize);
+ if (sizeOfEntries > expectedSize) {
+ ALOGE("ResTable_lib_header size %u is too small to fit %u entries (x %u).",
+ expectedSize, entryCount, (uint32_t)sizeof(ResTable_lib_entry));
+ return UNKNOWN_ERROR;
+ }
+
+ const ResTable_lib_entry* entry = (const ResTable_lib_entry*)(((uint8_t*) header) +
+ dtohl(header->header.headerSize));
+ for (uint32_t entryIndex = 0; entryIndex < entryCount; entryIndex++) {
+ uint32_t packageId = dtohl(entry->packageId);
+ char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
+ strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
+ LIB_NOISY(ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
+ dtohl(entry->packageId)));
+ if (packageId >= 256) {
+ ALOGE("Bad package id 0x%08x", packageId);
+ return UNKNOWN_ERROR;
+ }
+ mEntries.replaceValueFor(String16(tmpName), (uint8_t) packageId);
+ entry = entry + 1;
+ }
+ return NO_ERROR;
+}
+
+status_t DynamicRefTable::addMapping(const String16& packageName, uint8_t packageId)
+{
+ ssize_t index = mEntries.indexOfKey(packageName);
+ if (index < 0) {
+ return UNKNOWN_ERROR;
+ }
+ mLookupTable[mEntries.valueAt(index)] = packageId;
+ return NO_ERROR;
+}
+
+status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
+ uint32_t res = *resId;
+ size_t packageId = Res_GETPACKAGE(res) + 1;
+
+ if (packageId == APP_PACKAGE_ID) {
+ // No lookup needs to be done, app package IDs are absolute.
+ return NO_ERROR;
+ }
+
+ if (packageId == 0) {
+ // The package ID is 0x00. That means that a shared library is accessing
+ // its own local resource, so we fix up the resource with the calling
+ // package ID.
+ *resId |= ((uint32_t) mAssignedPackageId) << 24;
+ return NO_ERROR;
+ }
+
+ // Do a proper lookup.
+ uint8_t translatedId = mLookupTable[packageId];
+ if (translatedId == 0) {
+ ALOGV("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
+ (uint8_t)mAssignedPackageId, (uint8_t)packageId);
+ for (size_t i = 0; i < 256; i++) {
+ if (mLookupTable[i] != 0) {
+ ALOGV("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
+ }
+ }
+ return UNKNOWN_ERROR;
+ }
+
+ *resId = (res & 0x00ffffff) | (((uint32_t) translatedId) << 24);
+ return NO_ERROR;
+}
+
+status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
+ if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) {
+ return NO_ERROR;
+ }
+
+ status_t err = lookupResourceId(&value->data);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ value->dataType = Res_value::TYPE_REFERENCE;
+ return NO_ERROR;
+}
+
status_t ResTable::createIdmap(const ResTable& overlay,
uint32_t targetCrc, uint32_t overlayCrc,
const char* targetPath, const char* overlayPath,
@@ -5701,7 +5948,7 @@
continue;
}
if (N == 1) { // vector expected to hold (offset) + (N > 0 entries)
- ALOGW("idmap: type %d supposedly has entries, but no entries found\n", i);
+ ALOGW("idmap: type %u supposedly has entries, but no entries found\n", (uint32_t)i);
return UNKNOWN_ERROR;
}
*data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
@@ -5815,6 +6062,8 @@
printf("(null)\n");
} else if (value.dataType == Res_value::TYPE_REFERENCE) {
printf("(reference) 0x%08x\n", value.data);
+ } else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
+ printf("(dynamic reference) 0x%08x\n", value.data);
} else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
printf("(attribute) 0x%08x\n", value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
@@ -5897,6 +6146,11 @@
uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
+ // Since we are creating resID without actually
+ // iterating over them, we have no idea which is a
+ // dynamic reference. We must check.
+ pg->dynamicRefTable.lookupResourceId(&resID);
+
resource_name resName;
if (this->getResourceName(resID, true, &resName)) {
String8 type8;
@@ -5956,6 +6210,7 @@
uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
+ pg->dynamicRefTable.lookupResourceId(&resID);
resource_name resName;
if (this->getResourceName(resID, true, &resName)) {
String8 type8;
@@ -6034,8 +6289,14 @@
const uint8_t* baseMapPtr = (const uint8_t*)ent;
size_t mapOffset = esize;
const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
- printf(" Parent=0x%08x, Count=%d\n",
- dtohl(bagPtr->parent.ident), N);
+ const uint32_t parent = dtohl(bagPtr->parent.ident);
+ uint32_t resolvedParent = parent;
+ status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent);
+ if (err != NO_ERROR) {
+ resolvedParent = 0;
+ }
+ printf(" Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
+ parent, resolvedParent, N);
for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
printf(" #%i (Key=0x%08x): ",
i, dtohl(mapPtr->name.ident));
diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp
index 2c9f650..7a4dd13 100644
--- a/libs/androidfw/tests/ObbFile_test.cpp
+++ b/libs/androidfw/tests/ObbFile_test.cpp
@@ -91,7 +91,7 @@
EXPECT_EQ(sizeof(salt), saltLen)
<< "salt sizes were not the same";
- for (int i = 0; i < sizeof(salt); i++) {
+ for (size_t i = 0; i < sizeof(salt); i++) {
EXPECT_EQ(salt[i], newSalt[i])
<< "salt character " << i << " should be equal";
}
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index b2148b0..442e9ba 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -36,6 +36,7 @@
}
Patch::~Patch() {
+ delete[] vertices;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 8a44604..2f2debc 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -119,6 +119,17 @@
void PatchCache::removeDeferred(Res_png_9patch* patch) {
Mutex::Autolock _l(mLock);
+
+ // Assert that patch is not already garbage
+ size_t count = mGarbage.size();
+ for (size_t i = 0; i < count; i++) {
+ if (patch == mGarbage[i]) {
+ patch = NULL;
+ break;
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(patch == NULL);
+
mGarbage.push(patch);
}
@@ -143,8 +154,8 @@
for (size_t i = 0; i < patchesToRemove.size(); i++) {
const patch_pair_t& pair = patchesToRemove[i];
- // Add a new free block to the list
- const Patch* patch = pair.getSecond();
+ // Release the patch and mark the space in the free list
+ Patch* patch = pair.getSecond();
BufferBlock* block = new BufferBlock(patch->offset, patch->getSize());
block->next = mFreeBlocks;
mFreeBlocks = block;
@@ -152,6 +163,7 @@
mSize -= patch->getSize();
mCache.remove(*pair.getFirst());
+ delete patch;
}
#if DEBUG_PATCHES
@@ -216,6 +228,7 @@
} else {
mFreeBlocks = block->next;
}
+ delete block;
} else {
// Resize the block now that it's occupied
block->offset += size;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index e516bb8..5771299 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -172,6 +172,7 @@
.setContentTitle(r.getString(R.string.screenshot_saving_title))
.setContentText(r.getString(R.string.screenshot_saving_text))
.setSmallIcon(R.drawable.stat_notify_image)
+ .setCategory(Notification.CATEGORY_PROGRESS)
.setWhen(now);
mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
@@ -694,6 +695,7 @@
.setSmallIcon(R.drawable.stat_notify_image_error)
.setWhen(System.currentTimeMillis())
.setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
+ .setCategory(Notification.CATEGORY_ERROR)
.setAutoCancel(true);
Notification n =
new Notification.BigTextStyle(b)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 60ec787..3d5c5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -981,9 +981,9 @@
@Override
public void resetHeadsUpDecayTimer() {
+ mHandler.removeMessages(MSG_HIDE_HEADS_UP);
if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
&& mHeadsUpNotificationView.isClearable()) {
- mHandler.removeMessages(MSG_HIDE_HEADS_UP);
mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 0adb32f..481266b 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -312,6 +312,7 @@
mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
mUsbStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
+ mUsbStorageNotification.category = Notification.CATEGORY_SYSTEM;
final boolean adbOn = 1 == Settings.Global.getInt(
mContext.getContentResolver(),
@@ -404,6 +405,7 @@
mMediaStorageNotification.icon = icon;
mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
mMediaStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
+ mMediaStorageNotification.category = Notification.CATEGORY_SYSTEM;
}
final int notificationId = mMediaStorageNotification.icon;
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index d6c0c99..fb002d2 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -363,16 +363,17 @@
// Get the crop
RectF cropRect = mCropView.getCrop();
+ Point inSize = mCropView.getSourceDimensions();
+
// Due to rounding errors in the cropview renderer the edges can be slightly offset
// therefore we ensure that the boundaries are sanely defined
cropRect.left = Math.max(0, cropRect.left);
- cropRect.right = Math.min(mCropView.getWidth(), cropRect.right);
+ cropRect.right = Math.min(inSize.x, cropRect.right);
cropRect.top = Math.max(0, cropRect.top);
- cropRect.bottom = Math.min(mCropView.getHeight(), cropRect.bottom);
+ cropRect.bottom = Math.min(inSize.y, cropRect.bottom);
int cropRotation = mCropView.getImageRotation();
float cropScale = mCropView.getWidth() / (float) cropRect.width();
- Point inSize = mCropView.getSourceDimensions();
Matrix rotateMatrix = new Matrix();
rotateMatrix.setRotate(cropRotation);
float[] rotatedInSize = new float[] { inSize.x, inSize.y };
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0edce11..35f873e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -397,9 +397,8 @@
return true; // yes, recycle the event
}
if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
+ mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType());
mSecurityPolicy.updateEventSourceLocked(event);
- mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_ACTIVE_WINDOW,
- event.getWindowId(), event.getEventType()).sendToTarget();
notifyAccessibilityServicesDelayedLocked(event, false);
notifyAccessibilityServicesDelayedLocked(event, true);
}
@@ -503,7 +502,7 @@
mGlobalWindowTokens.put(windowId, windowToken.asBinder());
if (DEBUG) {
Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
- + " with windowId: " + windowId);
+ + " with windowId: " + windowId + " and token: " + windowToken.asBinder());
}
} else {
AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
@@ -514,12 +513,10 @@
userState.mWindowTokens.put(windowId, windowToken.asBinder());
if (DEBUG) {
Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
- + " with windowId: " + windowId + " and userId:" + mCurrentUserId);
+ + " with windowId: " + windowId + " and userId:" + mCurrentUserId
+ + " and token: " + windowToken.asBinder());
}
}
- if (DEBUG) {
- Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
- }
return windowId;
}
}
@@ -534,7 +531,7 @@
if (removedWindowId >= 0) {
if (DEBUG) {
Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
- + " with windowId: " + removedWindowId);
+ + " with windowId: " + removedWindowId + " and token: " + window.asBinder());
}
return;
}
@@ -548,7 +545,7 @@
if (DEBUG) {
Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
+ " with windowId: " + removedWindowIdForUser + " and userId:"
- + mUserStates.keyAt(i));
+ + mUserStates.keyAt(i) + " and token: " + window.asBinder());
}
return;
}
@@ -1622,7 +1619,6 @@
public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
- public static final int MSG_UPDATE_ACTIVE_WINDOW = 4;
public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
public static final int MSG_UPDATE_INPUT_FILTER = 6;
public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
@@ -1669,12 +1665,6 @@
sendStateToClientsForUser(0, userId);
} break;
- case MSG_UPDATE_ACTIVE_WINDOW: {
- final int windowId = msg.arg1;
- final int eventType = msg.arg2;
- mSecurityPolicy.updateActiveWindow(windowId, eventType);
- } break;
-
case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
announceNewUserIfNeeded();
} break;
@@ -3168,7 +3158,7 @@
}
}
- public void updateActiveWindow(int windowId, int eventType) {
+ public void updateActiveWindowLocked(int windowId, int eventType) {
// The active window is either the window that has input focus or
// the window that the user is currently touching. If the user is
// touching a window that does not have input focus as soon as the
@@ -3185,17 +3175,10 @@
// what the focused window is to update the active one.
// The active window also determined events from which
// windows are delivered.
- boolean focusedWindowActive = false;
synchronized (mLock) {
- if (mWindowsForAccessibilityCallback == null) {
- focusedWindowActive = true;
- }
- }
- if (focusedWindowActive) {
- if (windowId == getFocusedWindowId()) {
- synchronized (mLock) {
- mActiveWindowId = windowId;
- }
+ if (mWindowsForAccessibilityCallback == null
+ && windowId == getFocusedWindowId()) {
+ mActiveWindowId = windowId;
}
}
} break;
@@ -3337,7 +3320,9 @@
private int getFocusedWindowId() {
IBinder token = mWindowManagerService.getFocusedWindowToken();
- return findWindowIdLocked(token);
+ synchronized (mLock) {
+ return findWindowIdLocked(token);
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index b233943..abe362a 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -472,6 +472,7 @@
mTetheredNotification.tickerText = title;
mTetheredNotification.visibility = Notification.VISIBILITY_PUBLIC;
mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
+ mTetheredNotification.category = Notification.CATEGORY_STATUS;
notificationManager.notifyAsUser(null, mTetheredNotification.icon,
mTetheredNotification, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7c2de8b..00813c5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1242,7 +1242,6 @@
getContext().registerReceiver(mIntentReceiver, sdFilter);
mSettingsObserver = new SettingsObserver(mHandler);
- mSettingsObserver.observe();
// spin up NotificationScorers
String[] notificationScorerNames = resources.getStringArray(
@@ -1297,8 +1296,10 @@
// Grab our optional AudioService
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
- // make sure our listener services are properly bound
- rebindListenerServices();
+ } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ // This observer will force an update when observe is called, causing us to
+ // bind to listener services.
+ mSettingsObserver.observe();
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 9236bde..37547f2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1477,6 +1477,7 @@
// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
// system/core/run-as/run-as.c
// system/core/sdcard/sdcard.c
+ // external/libselinux/src/android.c:package_info_init()
//
sb.setLength(0);
sb.append(ai.packageName);
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 260e97a..eb38f4a 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -455,6 +455,7 @@
notification.flags |= Notification.FLAG_NO_CLEAR;
notification.setLatestEventInfo(context, title, details, intent);
notification.visibility = Notification.VISIBILITY_PUBLIC;
+ notification.category = Notification.CATEGORY_SYSTEM;
mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9ec7def..d5c7caa 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.PrivateApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
@@ -25,6 +26,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.telephony.Rlog;
import android.util.Log;
import com.android.internal.telephony.IPhoneSubInfo;
@@ -64,8 +66,41 @@
private static final String TAG = "TelephonyManager";
private static ITelephonyRegistry sRegistry;
+
+ private final HashMap<CallStateListener,Listener> mListeners
+ = new HashMap<CallStateListener,Listener>();
private final Context mContext;
+ private static class Listener extends ITelephonyListener.Stub {
+ final CallStateListener mListener;
+ private static final int WHAT = 1;
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ mListener.onCallStateChanged(msg.arg1, msg.arg2, (String)msg.obj);
+ }
+ };
+
+ Listener(CallStateListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onUpdate(final int callId, final int state, final String number) {
+ if (mHandler != null) {
+ mHandler.sendMessage(mHandler.obtainMessage(WHAT, callId, state, number));
+ }
+ }
+
+ void clearQueue() {
+ mHandler.removeMessages(WHAT);
+
+ // Don't accept more incoming binder calls either.
+ mHandler = null;
+ }
+ }
+
/** @hide */
public TelephonyManager(Context context) {
Context appContext = context.getApplicationContext();
@@ -87,38 +122,6 @@
}
private static TelephonyManager sInstance = new TelephonyManager();
- private HashMap<CallStateListener, Listener> mListeners
- = new HashMap<CallStateListener, Listener>();
-
- private static class Listener extends ITelephonyListener.Stub {
- final CallStateListener mListener;
- private static final int WHAT = 1;
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- mListener.onCallStateChanged(msg.arg1, msg.arg2, (String) msg.obj);
- }
- };
-
- Listener(CallStateListener listener) {
- mListener = listener;
- }
-
- @Override
- public void onUpdate(final int callId, final int state, final String number) {
- if (mHandler != null) {
- mHandler.sendMessage(mHandler.obtainMessage(WHAT, callId, state, number));
- }
- }
-
- void clearQueue() {
- mHandler.removeMessages(WHAT);
-
- // Don't accept more incoming binder calls either.
- mHandler = null;
- }
- }
/** @hide
/* @deprecated - use getSystemService as described above */
@@ -1920,439 +1923,369 @@
* Expose the rest of ITelephony to @PrivateApi
*/
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void dial(String number) {
try {
getITelephony().dial(number);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#dial");
+ Log.e(TAG, "Error calling ITelephony#dial", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void call(String callingPackage, String number) {
try {
getITelephony().call(callingPackage, number);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#call");
+ Log.e(TAG, "Error calling ITelephony#call", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean showCallScreen() {
try {
return getITelephony().showCallScreen();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#showCallScreen");
+ Log.e(TAG, "Error calling ITelephony#showCallScreen", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean showCallScreenWithDialpad(boolean showDialpad) {
try {
return getITelephony().showCallScreenWithDialpad(showDialpad);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#showCallScreenWithDialpad");
+ Log.e(TAG, "Error calling ITelephony#showCallScreenWithDialpad", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean endCall() {
try {
return getITelephony().endCall();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#endCall");
+ Log.e(TAG, "Error calling ITelephony#endCall", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void answerRingingCall() {
try {
getITelephony().answerRingingCall();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#answerRingingCall");
+ Log.e(TAG, "Error calling ITelephony#answerRingingCall", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void toggleHold() {
try {
getITelephony().toggleHold();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#toggleHold");
+ Log.e(TAG, "Error calling ITelephony#toggleHold", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void merge() {
try {
getITelephony().merge();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#merge");
+ Log.e(TAG, "Error calling ITelephony#merge", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void swap() {
try {
getITelephony().swap();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#swap");
+ Log.e(TAG, "Error calling ITelephony#swap", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void mute(boolean mute) {
try {
getITelephony().mute(mute);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#mute");
+ Log.e(TAG, "Error calling ITelephony#mute", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void silenceRinger() {
try {
getITelephony().silenceRinger();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#silenceRinger");
+ Log.e(TAG, "Error calling ITelephony#silenceRinger", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean isOffhook() {
try {
return getITelephony().isOffhook();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isOffhook");
+ Log.e(TAG, "Error calling ITelephony#isOffhook", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean isRinging() {
try {
return getITelephony().isRinging();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isRinging");
+ Log.e(TAG, "Error calling ITelephony#isRinging", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean isIdle() {
try {
return getITelephony().isIdle();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isIdle");
+ Log.e(TAG, "Error calling ITelephony#isIdle", e);
}
return true;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean isRadioOn() {
try {
return getITelephony().isRadioOn();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isRadioOn");
+ Log.e(TAG, "Error calling ITelephony#isRadioOn", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean isSimPinEnabled() {
try {
return getITelephony().isSimPinEnabled();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isSimPinEnabled");
+ Log.e(TAG, "Error calling ITelephony#isSimPinEnabled", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void cancelMissedCallsNotification() {
try {
getITelephony().cancelMissedCallsNotification();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#cancelMissedCallsNotification");
+ Log.e(TAG, "Error calling ITelephony#cancelMissedCallsNotification", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean supplyPin(String pin) {
try {
return getITelephony().supplyPin(pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPin");
+ Log.e(TAG, "Error calling ITelephony#supplyPin", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean supplyPuk(String puk, String pin) {
try {
return getITelephony().supplyPuk(puk, pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPuk");
+ Log.e(TAG, "Error calling ITelephony#supplyPuk", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public int[] supplyPinReportResult(String pin) {
try {
return getITelephony().supplyPinReportResult(pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPinReportResult");
+ Log.e(TAG, "Error calling ITelephony#supplyPinReportResult", e);
}
return new int[0];
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public int[] supplyPukReportResult(String puk, String pin) {
try {
return getITelephony().supplyPukReportResult(puk, pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#]");
+ Log.e(TAG, "Error calling ITelephony#]", e);
}
return new int[0];
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean handlePinMmi(String dialString) {
try {
return getITelephony().handlePinMmi(dialString);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#handlePinMmi");
+ Log.e(TAG, "Error calling ITelephony#handlePinMmi", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void toggleRadioOnOff() {
try {
getITelephony().toggleRadioOnOff();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#toggleRadioOnOff");
+ Log.e(TAG, "Error calling ITelephony#toggleRadioOnOff", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean setRadio(boolean turnOn) {
try {
return getITelephony().setRadio(turnOn);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#setRadio");
+ Log.e(TAG, "Error calling ITelephony#setRadio", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean setRadioPower(boolean turnOn) {
try {
return getITelephony().setRadioPower(turnOn);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#setRadioPower");
+ Log.e(TAG, "Error calling ITelephony#setRadioPower", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void updateServiceLocation() {
try {
getITelephony().updateServiceLocation();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#updateServiceLocation");
+ Log.e(TAG, "Error calling ITelephony#updateServiceLocation", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public int enableApnType(String type) {
try {
return getITelephony().enableApnType(type);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#enableApnType");
+ Log.e(TAG, "Error calling ITelephony#enableApnType", e);
}
return PhoneConstants.APN_REQUEST_FAILED;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public int disableApnType(String type) {
try {
return getITelephony().disableApnType(type);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#disableApnType");
+ Log.e(TAG, "Error calling ITelephony#disableApnType", e);
}
return PhoneConstants.APN_REQUEST_FAILED;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean enableDataConnectivity() {
try {
return getITelephony().enableDataConnectivity();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#enableDataConnectivity");
+ Log.e(TAG, "Error calling ITelephony#enableDataConnectivity", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean disableDataConnectivity() {
try {
return getITelephony().disableDataConnectivity();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#disableDataConnectivity");
+ Log.e(TAG, "Error calling ITelephony#disableDataConnectivity", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean isDataConnectivityPossible() {
try {
return getITelephony().isDataConnectivityPossible();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#isDataConnectivityPossible");
+ Log.e(TAG, "Error calling ITelephony#isDataConnectivityPossible", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public boolean needsOtaServiceProvisioning() {
try {
return getITelephony().needsOtaServiceProvisioning();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#needsOtaServiceProvisioning");
+ Log.e(TAG, "Error calling ITelephony#needsOtaServiceProvisioning", e);
}
return false;
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void playDtmfTone(char digit, boolean timedShortCode) {
try {
getITelephony().playDtmfTone(digit, timedShortCode);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#playDtmfTone");
+ Log.e(TAG, "Error calling ITelephony#playDtmfTone", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void stopDtmfTone() {
try {
getITelephony().stopDtmfTone();
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#stopDtmfTone");
+ Log.e(TAG, "Error calling ITelephony#stopDtmfTone", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void addCallStateListener(CallStateListener listener) {
try {
if (listener == null) {
@@ -2364,14 +2297,12 @@
getITelephony().addListener(l);
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#addListener");
+ Log.e(TAG, "Error calling ITelephony#addListener", e);
}
}
- /**
- * @hide
- * @PrivateApi
- */
+ /** @hide */
+ @PrivateApi
public void removeCallStateListener(CallStateListener listener) {
try {
final Listener l = mListeners.remove(listener);
@@ -2381,7 +2312,7 @@
getITelephony().removeListener(l);
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#removeListener");
+ Log.e(TAG, "Error calling ITelephony#removeListener", e);
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl b/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
index 8f5441c..c226217 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
@@ -23,16 +23,5 @@
* {@hide}
*/
oneway interface ITelephonyListener {
- /**
- * Notify of a new or updated call.
- * Any time the state of a call is updated, it will alert any listeners. This includes changes
- * of state such as when a call is put on hold or conferenced.
- *
- * @param callId a unique identifier for a given call that can be used to track state changes
- * @param state the new state of the call.
- * {@see com.android.services.telephony.common.Call$State}
- * @param number the phone number of the call. For some states, this may be blank. However, it
- * will be populated for any initial state.
- */
void onUpdate(int callId, int state, String number);
}
diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk
index 60ef92a..1d66bb9 100644
--- a/tests/SharedLibrary/client/Android.mk
+++ b/tests/SharedLibrary/client/Android.mk
@@ -3,7 +3,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_APK_LIBRARIES := SharedLibrary
+LOCAL_RES_LIBRARIES := SharedLibrary
LOCAL_PACKAGE_NAME := SharedLibraryClient
diff --git a/tests/SharedLibrary/client/AndroidManifest.xml b/tests/SharedLibrary/client/AndroidManifest.xml
index c6a43c0..a39c754 100644
--- a/tests/SharedLibrary/client/AndroidManifest.xml
+++ b/tests/SharedLibrary/client/AndroidManifest.xml
@@ -16,7 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.test.lib_client">
- <application android:label="@string/app_title">
+ <application android:label="@string/app_title" android:theme="@style/Theme">
<uses-library android:name="android.test.runner" />
<uses-library android:name="com.google.android.test.shared_library" />
<activity android:name="ActivityMain">
diff --git a/tests/SharedLibrary/client/res/layout/main.xml b/tests/SharedLibrary/client/res/layout/main.xml
new file mode 100644
index 0000000..067ef9f
--- /dev/null
+++ b/tests/SharedLibrary/client/res/layout/main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:id="@+id/label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@com.google.android.test.shared_library:string/shared_string"
+ style="@com.google.android.test.shared_library:style/CodeFont"/>
+
+ <com.google.android.test.shared_library.AddressView
+ xmlns:custom="http://schemas.android.com/apk/res/com.google.android.test.shared_library"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ custom:name="Professor Android"
+ custom:streetNumber="44"
+ custom:streetName="KitKat Lane"
+ custom:city="AndroidVille"
+ custom:state="OS"
+ custom:country="Mobile"
+ custom:zip="12345"/>
+</LinearLayout>
diff --git a/tests/SharedLibrary/client/res/values/strings.xml b/tests/SharedLibrary/client/res/values/strings.xml
index 3757a25..d9efdc7 100644
--- a/tests/SharedLibrary/client/res/values/strings.xml
+++ b/tests/SharedLibrary/client/res/values/strings.xml
@@ -16,4 +16,5 @@
<resources>
<string name="app_title">SharedLibrary client</string>
+ <string name="changes">@com.google.android.test.shared_library:string/shared_string</string>
</resources>
diff --git a/tests/SharedLibrary/client/res/values/themes.xml b/tests/SharedLibrary/client/res/values/themes.xml
new file mode 100644
index 0000000..a14f98a
--- /dev/null
+++ b/tests/SharedLibrary/client/res/values/themes.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <style name="Theme" parent="com.google.android.test.shared_library:Theme">
+ </style>
+</resources>
diff --git a/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java
index d6121a5..7276b3c 100644
--- a/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java
+++ b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java
@@ -18,18 +18,33 @@
import android.app.Activity;
import android.os.Bundle;
-import android.widget.TextView;
import com.google.android.test.shared_library.SharedLibraryMain;
public class ActivityMain extends Activity {
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
- TextView content = new TextView(this);
- content.setText("Library version: " + SharedLibraryMain.getVersion(this) + "!");
+ String[] expectedAnimals = new String[] {
+ "Racoon",
+ "Rhino",
+ "Elephant"
+ };
+
+ String[] animals = getResources().getStringArray(com.google.android.test.shared_library.R.array.animals);
+ if (animals == null || animals.length != expectedAnimals.length) {
+ throw new AssertionError("Animal list from shared library is null or wrong length.");
+ }
+
+ for (int i = 0; i < expectedAnimals.length; i++) {
+ if (!expectedAnimals[i].equals(animals[i])) {
+ throw new AssertionError("Expected '" + expectedAnimals[i]
+ + "' at index " + i + " but got '" + animals[i]);
+ }
+ }
SharedLibraryMain.ensureVersion(this, SharedLibraryMain.VERSION_BASE);
- setContentView(content);
}
}
diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk
index c19e23a..b2fc369 100644
--- a/tests/SharedLibrary/lib/Android.mk
+++ b/tests/SharedLibrary/lib/Android.mk
@@ -3,8 +3,13 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_AAPT_FLAGS := --shared-lib
LOCAL_PACKAGE_NAME := SharedLibrary
-LOCAL_MODULE_TAGS := tests
+LOCAL_EXPORT_PACKAGE_RESOURCES := true
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.proguard
include $(BUILD_PACKAGE)
diff --git a/tests/SharedLibrary/lib/proguard.proguard b/tests/SharedLibrary/lib/proguard.proguard
new file mode 100644
index 0000000..e5dfbe1
--- /dev/null
+++ b/tests/SharedLibrary/lib/proguard.proguard
@@ -0,0 +1,7 @@
+-keepparameternames
+-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
+ SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
+
+-keep public class * {
+ public protected *;
+}
diff --git a/tests/SharedLibrary/lib/res/layout/address.xml b/tests/SharedLibrary/lib/res/layout/address.xml
new file mode 100644
index 0000000..835f43e
--- /dev/null
+++ b/tests/SharedLibrary/lib/res/layout/address.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <TextView android:id="@+id/street"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <TextView android:id="@+id/cityStateZip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <TextView android:id="@+id/country"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</merge>
diff --git a/tests/SharedLibrary/lib/res/values/attrs.xml b/tests/SharedLibrary/lib/res/values/attrs.xml
new file mode 100644
index 0000000..8cefe92
--- /dev/null
+++ b/tests/SharedLibrary/lib/res/values/attrs.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <declare-styleable name="AddressView">
+ <attr name="name" format="string" />
+ <attr name="streetNumber" format="integer" />
+ <attr name="streetName" format="string" />
+ <attr name="city" format="string" />
+ <attr name="state" format="string" />
+ <attr name="zip" format="string" />
+ <attr name="country" format="string" />
+ </declare-styleable>
+</resources>
diff --git a/tests/SharedLibrary/lib/res/values/public.xml b/tests/SharedLibrary/lib/res/values/public.xml
new file mode 100644
index 0000000..37b1ec9
--- /dev/null
+++ b/tests/SharedLibrary/lib/res/values/public.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <public type="string" name="shared_string" id="0x00020003" />
+ <public type="style" name="CodeFont" id="0x00040000" />
+ <public type="style" name="Theme" id="0x00040001" />
+
+ <public type="attr" name="name" id="0x00010000" />
+ <public type="attr" name="streetNumber" id="0x00010001" />
+ <public type="attr" name="streetName" id="0x00010002" />
+ <public type="attr" name="city" id="0x00010003" />
+ <public type="attr" name="state" id="0x00010004" />
+ <public type="attr" name="zip" id="0x00010005" />
+ <public type="attr" name="country" id="0x00010006" />
+
+ <public type="array" name="animals" id="0x02050000" />
+</resources>
diff --git a/tests/SharedLibrary/lib/res/values/strings.xml b/tests/SharedLibrary/lib/res/values/strings.xml
index bbfb0b4..6827f93 100644
--- a/tests/SharedLibrary/lib/res/values/strings.xml
+++ b/tests/SharedLibrary/lib/res/values/strings.xml
@@ -19,4 +19,13 @@
<string name="upgrade_body"><xliff:g id="app">%1$s</xliff:g> requires a newer version
of <xliff:g id="lib">%2$s</xliff:g> to run.</string>
<string name="upgrade_button">Upgrade</string>
+ <string name="shared_string">Shared string!</string>
+
+ <string-array name="animals">
+ <item>@string/racoon</item>
+ <item>Rhino</item>
+ <item>Elephant</item>
+ </string-array>
+
+ <string name="racoon">Racoon</string>
</resources>
diff --git a/tests/SharedLibrary/lib/res/values/themes.xml b/tests/SharedLibrary/lib/res/values/themes.xml
new file mode 100644
index 0000000..f1081ac
--- /dev/null
+++ b/tests/SharedLibrary/lib/res/values/themes.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <style name="CodeFont" parent="@android:style/TextAppearance.Medium">
+ <item name="android:textColor">#00FF00</item>
+ <item name="android:typeface">monospace</item>
+ </style>
+
+ <style name="Theme" parent="android:Theme.Holo.Light">
+ <item name="android:actionBarStyle">@style/ActionBar</item>
+ </style>
+
+ <style name="ActionBar" parent="android:Widget.Holo.Light.ActionBar.Solid.Inverse">
+ <item name="android:background">@color/orange</item>
+ </style>
+
+ <color name="orange">#f0ad4e</color>
+</resources>
diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/AddressView.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/AddressView.java
new file mode 100644
index 0000000..dcaf68c
--- /dev/null
+++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/AddressView.java
@@ -0,0 +1,44 @@
+package com.google.android.test.shared_library;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class AddressView extends LinearLayout {
+ private TextView mNameView;
+ private TextView mStreetView;
+ private TextView mCityStateZipView;
+ private TextView mCountryView;
+
+ public AddressView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setOrientation(VERTICAL);
+
+ View view = LayoutInflater.from(context).inflate(R.layout.address, this);
+ mNameView = (TextView) view.findViewById(R.id.name);
+ mStreetView = (TextView) view.findViewById(R.id.street);
+ mCityStateZipView = (TextView) view.findViewById(R.id.cityStateZip);
+ mCountryView = (TextView) view.findViewById(R.id.country);
+
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.AddressView,
+ 0, 0);
+ try {
+ mNameView.setText(a.getString(R.styleable.AddressView_name));
+ int streetNumber = a.getInteger(R.styleable.AddressView_streetNumber, -1);
+ mStreetView.setText((streetNumber <= 0 ? "" : Integer.toString(streetNumber)) +
+ " " + a.getString(R.styleable.AddressView_streetName));
+ mCityStateZipView.setText(a.getString(R.styleable.AddressView_city) + ", " +
+ a.getString(R.styleable.AddressView_state) + " " +
+ a.getString(R.styleable.AddressView_zip));
+ mCountryView.setText(a.getString(R.styleable.AddressView_country));
+ } finally {
+ a.recycle();
+ }
+ }
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index f9a2d19..38bfa00 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1798,6 +1798,11 @@
return buf;
}
+void* AaptFile::editDataInRange(size_t offset, size_t size)
+{
+ return (void*)(((uint8_t*) editData(offset + size)) + offset);
+}
+
void* AaptFile::editData(size_t* outSize)
{
if (outSize) {
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 336d08b..82dda5f 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -251,6 +251,7 @@
size_t getSize() const { return mDataSize; }
void* editData(size_t size);
void* editData(size_t* outSize = NULL);
+ void* editDataInRange(size_t offset, size_t size);
void* padData(size_t wordSize);
status_t writeData(const void* data, size_t size);
void clearData();
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 49b8b55..d2eccbe 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -64,6 +64,7 @@
mProduct(NULL), mUseCrunchCache(false), mErrorOnFailedInsert(false),
mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
+ mBuildSharedLibrary(false),
mArgc(0), mArgv(NULL)
{}
~Bundle(void) {}
@@ -188,6 +189,8 @@
void setSingleCrunchInputFile(const char* val) { mSingleCrunchInputFile = val; }
const char* getSingleCrunchOutputFile() const { return mSingleCrunchOutputFile; }
void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; }
+ bool getBuildSharedLibrary() const { return mBuildSharedLibrary; }
+ void setBuildSharedLibrary(bool val) { mBuildSharedLibrary = val; }
/*
* Set and get the file specification.
@@ -300,6 +303,7 @@
const char* mOutputTextSymbols;
const char* mSingleCrunchInputFile;
const char* mSingleCrunchOutputFile;
+ bool mBuildSharedLibrary;
/* file specification */
int mArgc;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 33711fa..1cf4783 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -190,6 +190,9 @@
" Make the resources ID non constant. This is required to make an R java class\n"
" that does not contain the final value but is used to make reusable compiled\n"
" libraries that need to access resources.\n"
+ " --shared-lib\n"
+ " Make a shared library resource package that can be loaded by an application\n"
+ " at runtime to access the libraries resources. Implies --non-constant-id.\n"
" --error-on-failed-insert\n"
" Forces aapt to return an error if it fails to insert values into the manifest\n"
" with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
@@ -618,6 +621,9 @@
bundle.setProduct(argv[0]);
} else if (strcmp(cp, "-non-constant-id") == 0) {
bundle.setNonConstantId(true);
+ } else if (strcmp(cp, "-shared-lib") == 0) {
+ bundle.setNonConstantId(true);
+ bundle.setBuildSharedLibrary(true);
} else if (strcmp(cp, "-no-crunch") == 0) {
bundle.setUseCrunchCache(true);
} else if (strcmp(cp, "-ignore-assets") == 0) {
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index e03f4f6..d60a07fc 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -98,10 +98,10 @@
void ResourceIdCache::dump() {
printf("ResourceIdCache dump:\n");
- printf("Size: %ld\n", mIdMap.size());
- printf("Hits: %ld\n", mHits);
- printf("Misses: %ld\n", mMisses);
- printf("(Collisions: %ld)\n", mCollisions);
+ printf("Size: %zd\n", mIdMap.size());
+ printf("Hits: %zd\n", mHits);
+ printf("Misses: %zd\n", mMisses);
+ printf("(Collisions: %zd)\n", mCollisions);
}
}
diff --git a/tools/aapt/ResourceIdCache.h b/tools/aapt/ResourceIdCache.h
index e6bcda2..3acdee1 100644
--- a/tools/aapt/ResourceIdCache.h
+++ b/tools/aapt/ResourceIdCache.h
@@ -6,18 +6,20 @@
#ifndef RESOURCE_ID_CACHE_H
#define RESOURCE_ID_CACHE_H
+#include <utils/String16.h>
+
namespace android {
class ResourceIdCache {
public:
- static uint32_t lookup(const android::String16& package,
- const android::String16& type,
- const android::String16& name,
+ static uint32_t lookup(const String16& package,
+ const String16& type,
+ const String16& name,
bool onlyPublic);
- static uint32_t store(const android::String16& package,
- const android::String16& type,
- const android::String16& name,
+ static uint32_t store(const String16& package,
+ const String16& type,
+ const String16& name,
bool onlyPublic,
uint32_t resId);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 652998e..0fb2606 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1673,7 +1673,7 @@
ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage)
: mAssetsPackage(assetsPackage), mNextPackageId(1), mHaveAppPackage(false),
- mIsAppPackage(!bundle->getExtending()),
+ mIsAppPackage(!bundle->getExtending()), mIsSharedLibrary(bundle->getBuildSharedLibrary()),
mNumLocal(0),
mBundle(bundle)
{
@@ -1695,8 +1695,9 @@
const size_t N = incl.getBasePackageCount();
for (size_t phase=0; phase<2; phase++) {
for (size_t i=0; i<N; i++) {
- String16 name(incl.getBasePackageName(i));
+ const String16 name = incl.getBasePackageName(i);
uint32_t id = incl.getBasePackageId(i);
+
// First time through: only add base packages (id
// is not 0); second time through add the other
// packages.
@@ -1722,7 +1723,7 @@
}
}
if (id != 0) {
- NOISY(printf("Including package %s with ID=%d\n",
+ NOISY(fprintf(stderr, "Including package %s with ID=%d\n",
String8(name).string(), id));
sp<Package> p = new Package(name, id);
mPackages.add(name, p);
@@ -2687,6 +2688,9 @@
bool useUTF8 = !bundle->getUTF16StringsOption();
+ // The libraries this table references.
+ Vector<sp<Package> > libraryPackages;
+
// Iterate through all data, collecting all values (strings,
// references, etc).
StringPool valueStrings(useUTF8);
@@ -2694,8 +2698,22 @@
for (pi=0; pi<N; pi++) {
sp<Package> p = mOrderedPackages.itemAt(pi);
if (p->getTypes().size() == 0) {
- // Empty, skip!
+ // Empty, this is an imported package being used as
+ // a shared library. We do not flatten this package.
+ if (p->getAssignedId() != 0x01 && p->getName() != String16("android")) {
+ // This is not the base Android package, and it is a library
+ // so we must add a reference to the library when flattening.
+ libraryPackages.add(p);
+ }
continue;
+ } else if (p->getAssignedId() == 0x00) {
+ if (!bundle->getBuildSharedLibrary()) {
+ fprintf(stderr, "ERROR: Package %s can not have ID=0x00 unless building a shared library.",
+ String8(p->getName()).string());
+ return UNKNOWN_ERROR;
+ }
+ // If this is a shared library, we also include ourselves as an entry.
+ libraryPackages.add(p);
}
StringPool typeStrings(useUTF8);
@@ -2778,7 +2796,7 @@
}
ssize_t strAmt = 0;
-
+
// Now build the array of package chunks.
Vector<sp<AaptFile> > flatPackages;
for (pi=0; pi<N; pi++) {
@@ -2827,6 +2845,12 @@
return amt;
}
+ err = flattenLibraryTable(data, libraryPackages);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: failed to write library table\n");
+ return err;
+ }
+
// Build the type chunks inside of this package.
for (size_t ti=0; ti<N; ti++) {
// Retrieve them in the same order as the type string block.
@@ -3053,7 +3077,7 @@
fprintf(stderr, "**** value strings: %d\n", amt);
fprintf(stderr, "**** total strings: %d\n", strAmt);
#endif
-
+
for (pi=0; pi<flatPackages.size(); pi++) {
err = dest->writeData(flatPackages[pi]->getData(),
flatPackages[pi]->getSize());
@@ -3078,6 +3102,38 @@
return NO_ERROR;
}
+status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs) {
+ // Write out the library table if necessary
+ if (libs.size() > 0) {
+ NOISY(fprintf(stderr, "Writing library reference table\n"));
+
+ const size_t libStart = dest->getSize();
+ const size_t count = libs.size();
+ ResTable_lib_header* libHeader = (ResTable_lib_header*) dest->editDataInRange(libStart, sizeof(ResTable_lib_header));
+
+ memset(libHeader, 0, sizeof(*libHeader));
+ libHeader->header.type = htods(RES_TABLE_LIBRARY_TYPE);
+ libHeader->header.headerSize = htods(sizeof(*libHeader));
+ libHeader->header.size = htodl(sizeof(*libHeader) + (sizeof(ResTable_lib_entry) * count));
+ libHeader->count = htodl(count);
+
+ // Write the library entries
+ for (size_t i = 0; i < count; i++) {
+ const size_t entryStart = dest->getSize();
+ sp<Package> libPackage = libs[i];
+ NOISY(fprintf(stderr, " Entry %s -> 0x%02x\n",
+ String8(libPackage->getName()).string(),
+ (uint8_t)libPackage->getAssignedId()));
+
+ ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(entryStart, sizeof(ResTable_lib_entry));
+ memset(entry, 0, sizeof(*entry));
+ entry->packageId = htodl(libPackage->getAssignedId());
+ strcpy16_htod(entry->packageName, libPackage->getName().string());
+ }
+ }
+ return NO_ERROR;
+}
+
void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp)
{
fprintf(fp,
@@ -3847,7 +3903,7 @@
return NULL;
}
mHaveAppPackage = true;
- p = new Package(package, 127);
+ p = new Package(package, mIsSharedLibrary ? 0 : 127);
} else {
p = new Package(package, mNextPackageId);
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 75005cd..ec8fd175e 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -224,6 +224,7 @@
status_t validateLocalizations(void);
status_t flatten(Bundle*, const sp<AaptFile>& dest);
+ status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
void writePublicDefinitions(const String16& package, FILE* fp);
@@ -546,6 +547,7 @@
uint32_t mNextPackageId;
bool mHaveAppPackage;
bool mIsAppPackage;
+ bool mIsSharedLibrary;
size_t mNumLocal;
SourcePos mCurrentXmlPos;
Bundle* mBundle;
diff --git a/tools/aapt/printapk.cpp b/tools/aapt/printapk.cpp
index 4cf73d8..def6e2e 100644
--- a/tools/aapt/printapk.cpp
+++ b/tools/aapt/printapk.cpp
@@ -115,8 +115,8 @@
size_t basePackageCount = res.getBasePackageCount();
printf("Base Packages: %d\n", (int)basePackageCount);
for (size_t bpIndex=0; bpIndex<basePackageCount; bpIndex++) {
- const char16_t* ch = res.getBasePackageName(bpIndex);
- String8 s = String8(String16(ch));
+ const String16 ch = res.getBasePackageName(bpIndex);
+ String8 s = String8(ch);
printf(" [%3d] %s\n", (int)bpIndex, s.string());
}
#endif