summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManagerInternal.java2
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java4
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java4
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/app/Notification.java1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java32
-rw-r--r--core/java/android/content/pm/IPackageInstallerCallback.aidl2
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl2
-rw-r--r--core/java/android/content/pm/InstallSessionInfo.java30
-rw-r--r--core/java/android/content/pm/InstallSessionParams.java33
-rw-r--r--core/java/android/content/pm/PackageInstaller.java109
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java12
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl1
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareImpl.java4
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/UserManager.java5
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java88
-rw-r--r--core/java/android/text/style/TtsSpan.java4
-rw-r--r--core/java/android/view/RenderNode.java10
-rw-r--r--core/java/android/view/ViewOutlineProvider.java7
-rw-r--r--core/java/android/view/Window.java95
-rw-r--r--core/java/android/webkit/WebViewFactory.java271
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java77
-rw-r--r--core/java/com/android/internal/widget/ActionBarContainer.java30
24 files changed, 702 insertions, 129 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5262a5f..2a17fa6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -25,4 +25,6 @@ public abstract class ActivityManagerInternal {
// Called by the power manager.
public abstract void goingToSleep();
public abstract void wakingUp();
+ public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs,
+ String processName, String abiOverride, int uid, Runnable crashHandler);
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 1326064..b5d362d 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -256,7 +256,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
protected Transition getViewsTransition() {
if (mIsReturning) {
- return getWindow().getExitTransition();
+ return getWindow().getReenterTransition();
} else {
return getWindow().getEnterTransition();
}
@@ -264,7 +264,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
protected Transition getSharedElementTransition() {
if (mIsReturning) {
- return getWindow().getSharedElementExitTransition();
+ return getWindow().getSharedElementReenterTransition();
} else {
return getWindow().getSharedElementEnterTransition();
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 2ce6018..b3fdcc7 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -395,7 +395,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
protected Transition getViewsTransition() {
if (mIsReturning) {
- return getWindow().getEnterTransition();
+ return getWindow().getReturnTransition();
} else {
return getWindow().getExitTransition();
}
@@ -403,7 +403,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
protected Transition getSharedElementTransition() {
if (mIsReturning) {
- return getWindow().getSharedElementEnterTransition();
+ return getWindow().getSharedElementReturnTransition();
} else {
return getWindow().getSharedElementExitTransition();
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5347f03..772e132 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -454,7 +454,7 @@ public interface IActivityManager extends IInterface {
* Private non-Binder interfaces
*/
/* package */ boolean testIsSystemReady();
-
+
/** Information you can retrieve about a particular application. */
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c7fdbed..acf7ade 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -247,7 +247,6 @@ public class Notification implements Parcelable
/**
- * @hide
* A medium-format version of {@link #contentView}, providing the Notification an
* opportunity to add action buttons to contentView. At its discretion, the system UI may
* choose to show this as a heads-up notification, which will pop up so the user can see
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8be52a2..e28f00c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -449,9 +449,17 @@ public class DevicePolicyManager {
* active (enabled) in the system.
*/
public boolean isAdminActive(ComponentName who) {
+ return isAdminActiveAsUser(who, UserHandle.myUserId());
+ }
+
+ /**
+ * @see #isAdminActive(ComponentName)
+ * @hide
+ */
+ public boolean isAdminActiveAsUser(ComponentName who, int userId) {
if (mService != null) {
try {
- return mService.isAdminActive(who, UserHandle.myUserId());
+ return mService.isAdminActive(who, userId);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -465,9 +473,17 @@ public class DevicePolicyManager {
* returned.
*/
public List<ComponentName> getActiveAdmins() {
+ return getActiveAdminsAsUser(UserHandle.myUserId());
+ }
+
+ /**
+ * @see #getActiveAdmins()
+ * @hide
+ */
+ public List<ComponentName> getActiveAdminsAsUser(int userId) {
if (mService != null) {
try {
- return mService.getActiveAdmins(UserHandle.myUserId());
+ return mService.getActiveAdmins(userId);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2314,9 +2330,17 @@ public class DevicePolicyManager {
* @throws IllegalArgumentException if the userId is invalid.
*/
public ComponentName getProfileOwner() throws IllegalArgumentException {
+ return getProfileOwnerAsUser(Process.myUserHandle().getIdentifier());
+ }
+
+ /**
+ * @see #getProfileOwner()
+ * @hide
+ */
+ public ComponentName getProfileOwnerAsUser(final int userId) throws IllegalArgumentException {
if (mService != null) {
try {
- return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
+ return mService.getProfileOwner(userId);
} catch (RemoteException re) {
Log.w(TAG, "Failed to get profile owner");
throw new IllegalArgumentException(
@@ -2856,7 +2880,7 @@ public class DevicePolicyManager {
* @see #setAccountManagementDisabled
*/
public String[] getAccountTypesWithManagementDisabled() {
- return getAccountTypesWithManagementDisabledAsUser(UserHandle.getCallingUserId());
+ return getAccountTypesWithManagementDisabledAsUser(UserHandle.myUserId());
}
/**
diff --git a/core/java/android/content/pm/IPackageInstallerCallback.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl
index a31ae54..39ae1a0 100644
--- a/core/java/android/content/pm/IPackageInstallerCallback.aidl
+++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl
@@ -19,6 +19,8 @@ package android.content.pm;
/** {@hide} */
oneway interface IPackageInstallerCallback {
void onSessionCreated(int sessionId);
+ void onSessionOpened(int sessionId);
void onSessionProgressChanged(int sessionId, float progress);
+ void onSessionClosed(int sessionId);
void onSessionFinished(int sessionId, boolean success);
}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 2fd7ddb..af0323f 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -24,7 +24,9 @@ interface IPackageInstallerSession {
void setClientProgress(float progress);
void addClientProgress(float progress);
+ String[] list();
ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
+ ParcelFileDescriptor openRead(String name);
void close();
void commit(in IPackageInstallObserver2 observer);
diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java
index a9c574a..f263885 100644
--- a/core/java/android/content/pm/InstallSessionInfo.java
+++ b/core/java/android/content/pm/InstallSessionInfo.java
@@ -16,7 +16,9 @@
package android.content.pm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +34,8 @@ public class InstallSessionInfo implements Parcelable {
public String installerPackageName;
/** {@hide} */
public float progress;
+ /** {@hide} */
+ public boolean open;
/** {@hide} */
public int mode;
@@ -53,6 +57,7 @@ public class InstallSessionInfo implements Parcelable {
sessionId = source.readInt();
installerPackageName = source.readString();
progress = source.readFloat();
+ open = source.readInt() != 0;
mode = source.readInt();
sizeBytes = source.readLong();
@@ -88,6 +93,13 @@ public class InstallSessionInfo implements Parcelable {
}
/**
+ * Return if this session is currently open.
+ */
+ public boolean isOpen() {
+ return open;
+ }
+
+ /**
* Return the package name this session is working with. May be {@code null}
* if unknown.
*/
@@ -111,6 +123,23 @@ public class InstallSessionInfo implements Parcelable {
return appLabel;
}
+ /**
+ * Return an Intent that can be started to view details about this install
+ * session. This may surface actions such as pause, resume, or cancel.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard
+ * against this.
+ *
+ * @see PackageInstaller#ACTION_SESSION_DETAILS
+ */
+ public @Nullable Intent getDetailsIntent() {
+ final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+ intent.setPackage(installerPackageName);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -121,6 +150,7 @@ public class InstallSessionInfo implements Parcelable {
dest.writeInt(sessionId);
dest.writeString(installerPackageName);
dest.writeFloat(progress);
+ dest.writeInt(open ? 1 : 0);
dest.writeInt(mode);
dest.writeLong(sizeBytes);
diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java
index 3de9863..1716e39 100644
--- a/core/java/android/content/pm/InstallSessionParams.java
+++ b/core/java/android/content/pm/InstallSessionParams.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -30,6 +31,9 @@ import com.android.internal.util.IndentingPrintWriter;
*/
public class InstallSessionParams implements Parcelable {
+ /** {@hide} */
+ public static final int MODE_INVALID = -1;
+
/**
* Mode for an install session whose staged APKs should fully replace any
* existing APKs for the target app.
@@ -48,21 +52,19 @@ public class InstallSessionParams implements Parcelable {
public static final int MODE_INHERIT_EXISTING = 2;
/** {@hide} */
- public int mode;
+ public int mode = MODE_INVALID;
/** {@hide} */
public int installFlags;
/** {@hide} */
public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
/** {@hide} */
- public Signature[] signatures;
- /** {@hide} */
public long sizeBytes = -1;
/** {@hide} */
public String appPackageName;
/** {@hide} */
public Bitmap appIcon;
/** {@hide} */
- public CharSequence appLabel;
+ public String appLabel;
/** {@hide} */
public Uri originatingUri;
/** {@hide} */
@@ -86,7 +88,6 @@ public class InstallSessionParams implements Parcelable {
mode = source.readInt();
installFlags = source.readInt();
installLocation = source.readInt();
- signatures = (Signature[]) source.readParcelableArray(null);
sizeBytes = source.readLong();
appPackageName = source.readString();
appIcon = source.readParcelable(null);
@@ -106,16 +107,13 @@ public class InstallSessionParams implements Parcelable {
}
/**
- * Optionally provide a set of certificates for the app being installed.
- * <p>
- * If the APKs staged in the session aren't consistent with these
- * signatures, the install will fail. Regardless of this value, all APKs in
- * the app must have the same signing certificates.
- *
- * @see PackageInfo#signatures
+ * @deprecated use {@link PackageInstaller.Session#openRead(String)} to
+ * calculate message digest instead.
+ * @hide
*/
+ @Deprecated
public void setSignatures(@Nullable Signature[] signatures) {
- this.signatures = signatures;
+ throw new UnsupportedOperationException();
}
/**
@@ -146,7 +144,8 @@ public class InstallSessionParams implements Parcelable {
/**
* Optionally set an icon representing the app being installed. This should
- * be at least {@link android.R.dimen#app_icon_size} in both dimensions.
+ * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both
+ * dimensions.
*/
public void setAppIcon(@Nullable Bitmap appIcon) {
this.appIcon = appIcon;
@@ -156,7 +155,7 @@ public class InstallSessionParams implements Parcelable {
* Optionally set a label representing the app being installed.
*/
public void setAppLabel(@Nullable CharSequence appLabel) {
- this.appLabel = appLabel;
+ this.appLabel = (appLabel != null) ? appLabel.toString() : null;
}
/**
@@ -184,7 +183,6 @@ public class InstallSessionParams implements Parcelable {
pw.printPair("mode", mode);
pw.printHexPair("installFlags", installFlags);
pw.printPair("installLocation", installLocation);
- pw.printPair("signatures", (signatures != null));
pw.printPair("sizeBytes", sizeBytes);
pw.printPair("appPackageName", appPackageName);
pw.printPair("appIcon", (appIcon != null));
@@ -205,11 +203,10 @@ public class InstallSessionParams implements Parcelable {
dest.writeInt(mode);
dest.writeInt(installFlags);
dest.writeInt(installLocation);
- dest.writeParcelableArray(signatures, flags);
dest.writeLong(sizeBytes);
dest.writeString(appPackageName);
dest.writeParcelable(appIcon, flags);
- dest.writeString(appLabel != null ? appLabel.toString() : null);
+ dest.writeString(appLabel);
dest.writeParcelable(originatingUri, flags);
dest.writeParcelable(referrerUri, flags);
dest.writeString(abiOverride);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a114bb8..8af827e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -18,9 +18,10 @@ package android.content.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.PackageInstallObserver;
import android.app.PackageUninstallObserver;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.FileBridge;
import android.os.Handler;
@@ -32,7 +33,9 @@ import android.util.ExceptionUtils;
import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -63,6 +66,27 @@ import java.util.List;
* </ul>
*/
public class PackageInstaller {
+ /**
+ * Activity Action: Show details about a particular install session. This
+ * may surface actions such as pause, resume, or cancel.
+ * <p>
+ * This should always be scoped to the installer package that owns the
+ * session. Clients should use {@link InstallSessionInfo#getDetailsIntent()}
+ * to build this intent correctly.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard
+ * against this.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+
+ /**
+ * An integer session ID.
+ *
+ * @see #ACTION_SESSION_DETAILS
+ */
+ public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
+
private final PackageManager mPm;
private final IPackageInstaller mInstaller;
private final int mUserId;
@@ -180,14 +204,32 @@ public class PackageInstaller {
/**
* Events for observing session lifecycle.
+ * <p>
+ * A typical session lifecycle looks like this:
+ * <ul>
+ * <li>An installer creates a session to indicate pending app delivery. All
+ * install details are available at this point.
+ * <li>The installer opens the session to deliver APK data. Note that a
+ * session may be opened and closed multiple times as network connectivity
+ * changes. The installer may deliver periodic progress updates.
+ * <li>The installer commits or abandons the session, resulting in the
+ * session being finished.
+ * </ul>
*/
public static abstract class SessionCallback {
/**
- * New session has been created.
+ * New session has been created. Details about the session can be
+ * obtained from {@link PackageInstaller#getSessionInfo(int)}.
*/
public abstract void onCreated(int sessionId);
/**
+ * Session has been opened. A session is usually opened when the
+ * installer is actively writing data.
+ */
+ public abstract void onOpened(int sessionId);
+
+ /**
* Progress for given session has been updated.
* <p>
* Note that this progress may not directly correspond to the value
@@ -198,6 +240,11 @@ public class PackageInstaller {
public abstract void onProgressChanged(int sessionId, float progress);
/**
+ * Session has been closed.
+ */
+ public abstract void onClosed(int sessionId);
+
+ /**
* Session has completely finished, either with success or failure.
*/
public abstract void onFinished(int sessionId, boolean success);
@@ -207,8 +254,10 @@ public class PackageInstaller {
private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
Handler.Callback {
private static final int MSG_SESSION_CREATED = 1;
- private static final int MSG_SESSION_PROGRESS_CHANGED = 2;
- private static final int MSG_SESSION_FINISHED = 3;
+ private static final int MSG_SESSION_OPENED = 2;
+ private static final int MSG_SESSION_PROGRESS_CHANGED = 3;
+ private static final int MSG_SESSION_CLOSED = 4;
+ private static final int MSG_SESSION_FINISHED = 5;
final SessionCallback mCallback;
final Handler mHandler;
@@ -224,9 +273,15 @@ public class PackageInstaller {
case MSG_SESSION_CREATED:
mCallback.onCreated(msg.arg1);
return true;
+ case MSG_SESSION_OPENED:
+ mCallback.onOpened(msg.arg1);
+ return true;
case MSG_SESSION_PROGRESS_CHANGED:
mCallback.onProgressChanged(msg.arg1, (float) msg.obj);
return true;
+ case MSG_SESSION_CLOSED:
+ mCallback.onClosed(msg.arg1);
+ return true;
case MSG_SESSION_FINISHED:
mCallback.onFinished(msg.arg1, msg.arg2 != 0);
return true;
@@ -240,12 +295,22 @@ public class PackageInstaller {
}
@Override
+ public void onSessionOpened(int sessionId) {
+ mHandler.obtainMessage(MSG_SESSION_OPENED, sessionId, 0).sendToTarget();
+ }
+
+ @Override
public void onSessionProgressChanged(int sessionId, float progress) {
mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
.sendToTarget();
}
@Override
+ public void onSessionClosed(int sessionId) {
+ mHandler.obtainMessage(MSG_SESSION_CLOSED, sessionId, 0).sendToTarget();
+ }
+
+ @Override
public void onSessionFinished(int sessionId, boolean success) {
mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
.sendToTarget();
@@ -373,7 +438,7 @@ public class PackageInstaller {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
- throw new IOException(e);
+ throw e.rethrowAsRuntimeException();
}
}
@@ -391,6 +456,40 @@ public class PackageInstaller {
}
/**
+ * List all APK names contained in this session.
+ * <p>
+ * This returns all names which have been previously written through
+ * {@link #openWrite(String, long, long)} as part of this session.
+ */
+ public @NonNull String[] list() {
+ try {
+ return mSession.list();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Open a stream to read an APK file from the session.
+ * <p>
+ * This is only valid for names which have been previously written
+ * through {@link #openWrite(String, long, long)} as part of this
+ * session. For example, this stream may be used to calculate a
+ * {@link MessageDigest} of a written APK before committing.
+ */
+ public @NonNull InputStream openRead(@NonNull String name) throws IOException {
+ try {
+ final ParcelFileDescriptor pfd = mSession.openRead(name);
+ return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ } catch (RuntimeException e) {
+ ExceptionUtils.maybeUnwrapIOException(e);
+ throw e;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Attempt to commit everything staged in this session. This may require
* user intervention, and so it may not happen immediately. The final
* result of the commit will be reported through the given callback.
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
index 27829a7..6e1844a 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -65,6 +65,18 @@ public final class HdmiCecDeviceInfo implements Parcelable {
*/
public static final int ADDR_INTERNAL = 0;
+ /**
+ * Physical address used to indicate the source comes from internal device.
+ * The physical address of TV(0) is used.
+ */
+ public static final int PATH_INTERNAL = 0x0000;
+
+ /** Invalid physical address (routing path) */
+ public static final int PATH_INVALID = 0xFFFF;
+
+ /** Invalid port ID */
+ public static final int PORT_INVALID = -1;
+
// Logical address, physical address, device type, vendor id and display name
// are immutable value.
private final int mLogicalAddress;
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 808e0c9..920a1f4 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -37,6 +37,7 @@ import java.util.List;
*/
interface IHdmiControlService {
int[] getSupportedTypes();
+ HdmiCecDeviceInfo getActiveSource();
void oneTouchPlay(IHdmiControlCallback callback);
void queryDisplayStatus(IHdmiControlCallback callback);
void addHotplugEventListener(IHdmiHotplugEventListener listener);
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 6734878..5c7a8da 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -139,8 +139,8 @@ public final class GeofenceHardwareImpl {
private void updateFusedHardwareAvailability() {
boolean fusedSupported;
try {
- fusedSupported = mFusedService.isSupported();
- } catch(RemoteException e) {
+ fusedSupported = (mFusedService != null ? mFusedService.isSupported() : false);
+ } catch (RemoteException e) {
Log.e(TAG, "RemoteException calling LocationManagerService");
fusedSupported = false;
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index afac239..c3ac012 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -61,6 +61,12 @@ public class Process {
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
/**
+ * Defines the root UID.
+ * @hide
+ */
+ public static final int ROOT_UID = 0;
+
+ /**
* Defines the UID/GID under which system code runs.
*/
public static final int SYSTEM_UID = 1000;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d385131..13f93a7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -625,8 +625,9 @@ public class UserManager {
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
try {
- mService.setUserRestrictions(
- mService.getDefaultGuestRestrictions(), guest.id);
+ Bundle guestRestrictions = mService.getDefaultGuestRestrictions();
+ guestRestrictions.putBoolean(DISALLOW_SMS, true);
+ mService.setUserRestrictions(guestRestrictions, guest.id);
} catch (RemoteException re) {
Log.w(TAG, "Could not update guest restrictions");
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 3f53ad4..5248131 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -45,18 +45,22 @@ public class AlwaysOnHotwordDetector {
* Indicates that this hotword detector is no longer valid for any recognition
* and should not be used anymore.
*/
- public static final int STATE_INVALID = -3;
+ private static final int STATE_INVALID = -3;
+
/**
* Indicates that recognition for the given keyphrase is not available on the system
* because of the hardware configuration.
+ * No further interaction should be performed with the detector that returns this availability.
*/
public static final int STATE_HARDWARE_UNAVAILABLE = -2;
/**
* Indicates that recognition for the given keyphrase is not supported.
+ * No further interaction should be performed with the detector that returns this availability.
*/
public static final int STATE_KEYPHRASE_UNSUPPORTED = -1;
/**
* Indicates that the given keyphrase is not enrolled.
+ * The caller may choose to begin an enrollment flow for the keyphrase.
*/
public static final int STATE_KEYPHRASE_UNENROLLED = 1;
/**
@@ -91,12 +95,14 @@ public class AlwaysOnHotwordDetector {
// Must be kept in sync with the related attribute defined as searchKeyphraseRecognitionFlags.
/**
- * Simple recognition of the key phrase. Returned by {@link #getSupportedRecognitionModes()}
+ * Simple recognition of the key phrase.
+ * Returned by {@link #getSupportedRecognitionModes()}
*/
public static final int RECOGNITION_MODE_VOICE_TRIGGER
= SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
/**
- * Trigger only if one user is identified. Returned by {@link #getSupportedRecognitionModes()}
+ * User identification performed with the keyphrase recognition.
+ * Returned by {@link #getSupportedRecognitionModes()}
*/
public static final int RECOGNITION_MODE_USER_IDENTIFICATION
= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
@@ -149,16 +155,11 @@ public class AlwaysOnHotwordDetector {
*
* Availability implies whether the hardware on this system is capable of listening for
* the given keyphrase or not. <p/>
- * If the return code is one of {@link #STATE_HARDWARE_UNAVAILABLE} or
- * {@link #STATE_KEYPHRASE_UNSUPPORTED},
- * detection is not possible and no further interaction should be
- * performed with this detector. <br/>
- * If it is {@link #STATE_KEYPHRASE_UNENROLLED} the caller may choose to begin
- * an enrollment flow for the keyphrase. <br/>
- * and for {@link #STATE_KEYPHRASE_ENROLLED} a recognition can be started as desired. <p/>
*
- * If the return code is {@link #STATE_INVALID}, this detector is stale.
- * A new detector should be obtained for use in the future.
+ * @see AlwaysOnHotwordDetector#STATE_HARDWARE_UNAVAILABLE
+ * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNSUPPORTED
+ * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNENROLLED
+ * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_ENROLLED
*/
void onAvailabilityChanged(int status);
/**
@@ -217,9 +218,15 @@ public class AlwaysOnHotwordDetector {
/**
* Gets the recognition modes supported by the associated keyphrase.
*
+ * @see #RECOGNITION_MODE_USER_IDENTIFICATION
+ * @see #RECOGNITION_MODE_VOICE_TRIGGER
+ *
* @throws UnsupportedOperationException if the keyphrase itself isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * @throws IllegalStateException if the detector is in an invalid state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
public int getSupportedRecognitionModes() {
synchronized (mLock) {
@@ -228,6 +235,11 @@ public class AlwaysOnHotwordDetector {
}
private int getSupportedRecognitionModesLocked() {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException(
+ "getSupportedRecognitionModes called on an invalid detector");
+ }
+
// This method only makes sense if we can actually support a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED
&& mAvailability != STATE_KEYPHRASE_UNENROLLED) {
@@ -247,9 +259,16 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * @throws IllegalStateException if the detector is in an invalid state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
public void startRecognition(int recognitionFlags) {
synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("startRecognition called on an invalid detector");
+ }
+
// Check if we can start/stop a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED) {
throw new UnsupportedOperationException(
@@ -268,9 +287,16 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * @throws IllegalStateException if the detector is in an invalid state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
public void stopRecognition() {
synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("stopRecognition called on an invalid detector");
+ }
+
// Check if we can start/stop a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED) {
throw new UnsupportedOperationException(
@@ -293,14 +319,28 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if managing they keyphrase isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * @throws IllegalStateException if the detector is in an invalid state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
public Intent getManageIntent(int action) {
+ synchronized (mLock) {
+ return getManageIntentLocked(action);
+ }
+ }
+
+ private Intent getManageIntentLocked(int action) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("getManageIntent called on an invalid detector");
+ }
+
// This method only makes sense if we can actually support a recognition.
if (mAvailability != STATE_KEYPHRASE_ENROLLED
&& mAvailability != STATE_KEYPHRASE_UNENROLLED) {
throw new UnsupportedOperationException(
"Managing the given keyphrase is not supported");
}
+
if (action != MANAGE_ACTION_ENROLL
&& action != MANAGE_ACTION_RE_ENROLL
&& action != MANAGE_ACTION_UN_ENROLL) {
@@ -387,7 +427,6 @@ public class AlwaysOnHotwordDetector {
if (DBG) Slog.d(TAG, "starting recognition...");
int status = startRecognitionLocked();
if (status == STATUS_OK) {
- mInternalState |= FLAG_STARTED;
mHandler.sendEmptyMessage(MSG_DETECTION_STARTED);
} else {
if (DBG) Slog.d(TAG, "failed to start recognition: " + status);
@@ -404,7 +443,6 @@ public class AlwaysOnHotwordDetector {
if (DBG) Slog.d(TAG, "stopping recognition...");
int status = stopRecognitionLocked();
if (status == STATUS_OK) {
- mInternalState &= ~FLAG_STARTED;
if (!requested) mHandler.sendEmptyMessage(MSG_DETECTION_STOPPED);
} else {
if (!requested) mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
@@ -483,20 +521,42 @@ public class AlwaysOnHotwordDetector {
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ Slog.w(TAG, "Received message: " + msg.what + " for an invalid detector");
+ return;
+ }
+ }
+
switch (msg.what) {
case MSG_STATE_CHANGED:
mExternalCallback.onAvailabilityChanged(msg.arg1);
break;
case MSG_HOTWORD_DETECTED:
+ synchronized (mLock) {
+ mInternalState &= ~FLAG_REQUESTED;
+ mInternalState &= ~FLAG_STARTED;
+ }
mExternalCallback.onDetected((byte[]) msg.obj);
break;
case MSG_DETECTION_STARTED:
+ synchronized (mLock) {
+ mInternalState |= FLAG_STARTED;
+ }
mExternalCallback.onDetectionStarted();
break;
case MSG_DETECTION_STOPPED:
+ synchronized (mLock) {
+ mInternalState &= ~FLAG_REQUESTED;
+ mInternalState &= ~FLAG_STARTED;
+ }
mExternalCallback.onDetectionStopped();
break;
case MSG_DETECTION_ERROR:
+ synchronized (mLock) {
+ mInternalState &= ~FLAG_REQUESTED;
+ mInternalState &= ~FLAG_STARTED;
+ }
mExternalCallback.onError();
break;
default:
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index f3a48a6..cb447fd 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -518,7 +518,7 @@ public class TtsSpan implements ParcelableSpan {
* This class uses generics so methods from this class can return instances
* of its child classes, resulting in a fluent API (CRTP pattern).
*/
- public static abstract class Builder<C extends Builder<C>> {
+ public static class Builder<C extends Builder<?>> {
// Holds the type of this class.
private final String mType;
@@ -580,7 +580,7 @@ public class TtsSpan implements ParcelableSpan {
* this builder like {@link TtsSpan.TextBuilder} and
* {@link TtsSpan.CardinalBuilder} are likely more useful.
*/
- public static class SemioticClassBuilder<C extends SemioticClassBuilder<C>>
+ public static class SemioticClassBuilder<C extends SemioticClassBuilder<?>>
extends Builder<C> {
public SemioticClassBuilder(String type) {
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index e9ec565..eee4973 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -355,9 +355,10 @@ public class RenderNode {
return nSetOutlineEmpty(mNativeRenderNode);
} else if (outline.mRect != null) {
return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
- outline.mRect.right, outline.mRect.bottom, outline.mRadius);
+ outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
} else if (outline.mPath != null) {
- return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath);
+ return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
+ outline.mAlpha);
}
throw new IllegalArgumentException("Unrecognized outline?");
}
@@ -849,8 +850,9 @@ public class RenderNode {
private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
- int right, int bottom, float radius);
- private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath);
+ int right, int bottom, float radius, float alpha);
+ private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
+ float alpha);
private static native boolean nSetOutlineEmpty(long renderNode);
private static native boolean nSetOutlineNone(long renderNode);
private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
diff --git a/core/java/android/view/ViewOutlineProvider.java b/core/java/android/view/ViewOutlineProvider.java
index 64624ae..4054031 100644
--- a/core/java/android/view/ViewOutlineProvider.java
+++ b/core/java/android/view/ViewOutlineProvider.java
@@ -25,7 +25,8 @@ import android.graphics.drawable.Drawable;
public abstract class ViewOutlineProvider {
/**
* Default outline provider for Views, which queries the Outline from the View's background,
- * or returns <code>false</code> if the View does not have a background.
+ * or generates a 0 alpha, rectangular Outline the size of the View if a background
+ * isn't present.
*
* @see Drawable#getOutline(Outline)
*/
@@ -35,6 +36,10 @@ public abstract class ViewOutlineProvider {
Drawable background = view.getBackground();
if (background != null) {
background.getOutline(outline);
+ } else {
+
+ outline.setRect(0, 0, view.getWidth(), view.getHeight());
+ outline.setAlpha(0.0f);
}
}
};
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index c169d35..e7b3152 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1425,6 +1425,21 @@ public abstract class Window {
public void setEnterTransition(Transition transition) {}
/**
+ * Sets the Transition that will be used to move Views out of the scene when the Window is
+ * preparing to close, for example after a call to
+ * {@link android.app.Activity#finishAfterTransition()}. The exiting
+ * Views will be those that are regular Views or ViewGroups that have
+ * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as entering is governed by changing visibility from
+ * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null,
+ * entering Views will remain unaffected. If nothing is set, the default will be to
+ * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}.
+ * @param transition The Transition to use to move Views out of the Scene when the Window
+ * is preparing to close.
+ */
+ public void setReturnTransition(Transition transition) {}
+
+ /**
* Sets the Transition that will be used to move Views out of the scene when starting a
* new Activity. The exiting Views will be those that are regular Views or ViewGroups that
* have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
@@ -1437,6 +1452,20 @@ public abstract class Window {
public void setExitTransition(Transition transition) {}
/**
+ * Sets the Transition that will be used to move Views in to the scene when returning from
+ * a previously-started Activity. The entering Views will be those that are regular Views
+ * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions
+ * will extend {@link android.transition.Visibility} as exiting is governed by changing
+ * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null,
+ * the views will remain unaffected. If nothing is set, the default will be to use the same
+ * transition as {@link #setExitTransition(android.transition.Transition)}.
+ * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ * @param transition The Transition to use to move Views into the scene when reentering from a
+ * previously-started Activity.
+ */
+ public void setReenterTransition(Transition transition) {}
+
+ /**
* Returns the transition used to move Views into the initial scene. The entering
* Views will be those that are regular Views or ViewGroups that have
* {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
@@ -1449,6 +1478,19 @@ public abstract class Window {
public Transition getEnterTransition() { return null; }
/**
+ * Returns he Transition that will be used to move Views out of the scene when the Window is
+ * preparing to close, for example after a call to
+ * {@link android.app.Activity#finishAfterTransition()}. The exiting
+ * Views will be those that are regular Views or ViewGroups that have
+ * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as entering is governed by changing visibility from
+ * {@link View#VISIBLE} to {@link View#INVISIBLE}.
+ * @return The Transition to use to move Views out of the Scene when the Window
+ * is preparing to close.
+ */
+ public Transition getReturnTransition() { return null; }
+
+ /**
* Returns the Transition that will be used to move Views out of the scene when starting a
* new Activity. The exiting Views will be those that are regular Views or ViewGroups that
* have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
@@ -1461,6 +1503,18 @@ public abstract class Window {
public Transition getExitTransition() { return null; }
/**
+ * Returns the Transition that will be used to move Views in to the scene when returning from
+ * a previously-started Activity. The entering Views will be those that are regular Views
+ * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions
+ * will extend {@link android.transition.Visibility} as exiting is governed by changing
+ * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}.
+ * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ * @return The Transition to use to move Views into the scene when reentering from a
+ * previously-started Activity.
+ */
+ public Transition getReenterTransition() { return null; }
+
+ /**
* Sets the Transition that will be used for shared elements transferred into the content
* Scene. Typical Transitions will affect size and location, such as
* {@link android.transition.ChangeBounds}. A null
@@ -1472,6 +1526,19 @@ public abstract class Window {
public void setSharedElementEnterTransition(Transition transition) {}
/**
+ * Sets the Transition that will be used for shared elements transferred back to a
+ * calling Activity. Typical Transitions will affect size and location, such as
+ * {@link android.transition.ChangeBounds}. A null
+ * value will cause transferred shared elements to blink to the final position.
+ * If no value is set, the default will be to use the same value as
+ * {@link #setSharedElementEnterTransition(android.transition.Transition)}.
+ * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ * @param transition The Transition to use for shared elements transferred out of the content
+ * Scene.
+ */
+ public void setSharedElementReturnTransition(Transition transition) {}
+
+ /**
* Returns the Transition that will be used for shared elements transferred into the content
* Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @return Transition to use for sharend elements transferred into the content Scene.
@@ -1479,6 +1546,13 @@ public abstract class Window {
public Transition getSharedElementEnterTransition() { return null; }
/**
+ * Returns the Transition that will be used for shared elements transferred back to a
+ * calling Activity. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ * @return Transition to use for sharend elements transferred into the content Scene.
+ */
+ public Transition getSharedElementReturnTransition() { return null; }
+
+ /**
* Sets the Transition that will be used for shared elements after starting a new Activity
* before the shared elements are transferred to the called Activity. If the shared elements
* must animate during the exit transition, this Transition should be used. Upon completion,
@@ -1490,6 +1564,17 @@ public abstract class Window {
public void setSharedElementExitTransition(Transition transition) {}
/**
+ * Sets the Transition that will be used for shared elements reentering from a started
+ * Activity after it has returned the shared element to it start location. If no value
+ * is set, this will default to
+ * {@link #setSharedElementExitTransition(android.transition.Transition)}.
+ * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ * @param transition The Transition to use for shared elements in the launching Window
+ * after the shared element has returned to the Window.
+ */
+ public void setSharedElementReenterTransition(Transition transition) {}
+
+ /**
* Returns the Transition to use for shared elements in the launching Window prior
* to transferring to the launched Activity's Window.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
@@ -1500,6 +1585,16 @@ public abstract class Window {
public Transition getSharedElementExitTransition() { return null; }
/**
+ * Returns the Transition that will be used for shared elements reentering from a started
+ * Activity after it has returned the shared element to it start location.
+ * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
+ * @return the Transition that will be used for shared elements reentering from a started
+ * Activity after it has returned the shared element to it start location.
+ */
+ public Transition getSharedElementReenterTransition() { return null; }
+
+ /**
* Controls how the transition set in
* {@link #setEnterTransition(android.transition.Transition)} overlaps with the exit
* transition of the calling Activity. When true, the transition will start as soon as possible.
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 2c7b3eb..2e836fb 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -16,16 +16,26 @@
package android.webkit;
+import android.app.ActivityManagerInternal;
+import android.app.Application;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import com.android.server.LocalServices;
import dalvik.system.VMRuntime;
import java.io.File;
+import java.util.Arrays;
import com.android.internal.os.Zygote;
@@ -42,17 +52,15 @@ public final class WebViewFactory {
private static final String NULL_WEBVIEW_FACTORY =
"com.android.webview.nullwebview.NullWebViewFactoryProvider";
- // TODO(torne): we need to use a system property instead of hardcoding the library paths to
- // enable it to be changed when a webview update apk is installed.
- private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_32 =
- "/system/lib/libwebviewchromium.so";
- private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_64 =
- "/system/lib64/libwebviewchromium.so";
private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
"/data/misc/shared_relro/libwebviewchromium32.relro";
private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
"/data/misc/shared_relro/libwebviewchromium64.relro";
+ public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
+ "persist.sys.webview.vmsize";
+ private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
+
private static final String LOGTAG = "WebViewFactory";
private static final boolean DEBUG = false;
@@ -64,8 +72,8 @@ public final class WebViewFactory {
private static boolean sAddressSpaceReserved = false;
public static String getWebViewPackageName() {
- // TODO: Make this dynamic based on resource configuration.
- return "com.android.webview";
+ return AppGlobals.getInitialApplication().getString(
+ com.android.internal.R.string.config_webViewPackageName);
}
static WebViewFactoryProvider getProvider() {
@@ -99,10 +107,18 @@ public final class WebViewFactory {
}
private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
+ Application initialApplication = AppGlobals.getInitialApplication();
try {
- return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
- } catch (ClassNotFoundException e) {
- Log.e(LOGTAG, "Chromium WebView does not exist");
+ Context webViewContext = initialApplication.createPackageContext(
+ getWebViewPackageName(),
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ initialApplication.getAssets().addAssetPath(
+ webViewContext.getApplicationInfo().sourceDir);
+ ClassLoader clazzLoader = webViewContext.getClassLoader();
+ return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
+ clazzLoader);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOGTAG, "Chromium WebView package does not exist");
return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
}
}
@@ -114,79 +130,197 @@ public final class WebViewFactory {
public static void prepareWebViewInZygote() {
try {
System.loadLibrary("webviewchromium_loader");
- sAddressSpaceReserved = nativeReserveAddressSpace(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
- CHROMIUM_WEBVIEW_NATIVE_LIB_64);
+ long addressSpaceToReserve =
+ SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
+
if (sAddressSpaceReserved) {
- if (DEBUG) Log.v(LOGTAG, "address space reserved");
+ if (DEBUG) {
+ Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
+ }
} else {
- Log.e(LOGTAG, "reserving address space failed");
+ Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
+ " bytes of address space failed");
}
- } catch (Throwable e) {
+ } catch (Throwable t) {
// Log and discard errors at this stage as we must not crash the zygote.
- Log.e(LOGTAG, "error preparing native loader", e);
+ Log.e(LOGTAG, "error preparing native loader", t);
}
}
/**
* Perform any WebView loading preparations that must happen at boot from the system server,
- * after the package manager has started.
+ * after the package manager has started or after an update to the webview is installed.
* This must be called in the system server.
* Currently, this means spawning the child processes which will create the relro files.
*/
public static void prepareWebViewInSystemServer() {
+ String[] nativePaths = null;
+ try {
+ nativePaths = getWebViewNativeLibraryPaths();
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ prepareWebViewInSystemServer(nativePaths);
+ }
+
+ private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
if (DEBUG) Log.v(LOGTAG, "creating relro files");
- if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_64).exists()) {
- createRelroFile(Build.SUPPORTED_64_BIT_ABIS[0]);
+
+ // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
+ // unexpected values will be handled there to ensure that we trigger notifying any process
+ // waiting on relreo creation.
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
+ createRelroFile(false /* is64Bit */, nativeLibraryPaths);
+ }
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
+ createRelroFile(true /* is64Bit */, nativeLibraryPaths);
}
- if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_32).exists()) {
- createRelroFile(Build.SUPPORTED_32_BIT_ABIS[0]);
+ }
+
+ public static void onWebViewUpdateInstalled() {
+ String[] nativeLibs = null;
+ try {
+ nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+
+ if (nativeLibs != null) {
+ long newVmSize = 0L;
+
+ for (String path : nativeLibs) {
+ if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
+ if (path == null) continue;
+ File f = new File(path);
+ if (f.exists()) {
+ long length = f.length();
+ if (length > newVmSize) {
+ newVmSize = length;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Log.v(LOGTAG, "Based on library size, need " + newVmSize +
+ " bytes of address space.");
+ }
+ // The required memory can be larger than the file on disk (due to .bss), and an
+ // upgraded version of the library will likely be larger, so always attempt to reserve
+ // twice as much as we think to allow for the library to grow during this boot cycle.
+ newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ Log.d(LOGTAG, "Setting new address space to " + newVmSize);
+ SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ Long.toString(newVmSize));
+ }
+ prepareWebViewInSystemServer(nativeLibs);
+ }
+
+ private static String[] getWebViewNativeLibraryPaths()
+ throws PackageManager.NameNotFoundException {
+ final String NATIVE_LIB_FILE_NAME = "libwebviewchromium.so";
+
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ ApplicationInfo ai = pm.getApplicationInfo(getWebViewPackageName(), 0);
+
+ String path32;
+ String path64;
+ boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
+ if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
+ // Multi-arch case.
+ if (primaryArchIs64bit) {
+ // Primary arch: 64-bit, secondary: 32-bit.
+ path64 = ai.nativeLibraryDir;
+ path32 = ai.secondaryNativeLibraryDir;
+ } else {
+ // Primary arch: 32-bit, secondary: 64-bit.
+ path64 = ai.secondaryNativeLibraryDir;
+ path32 = ai.nativeLibraryDir;
+ }
+ } else if (primaryArchIs64bit) {
+ // Single-arch 64-bit.
+ path64 = ai.nativeLibraryDir;
+ path32 = "";
+ } else {
+ // Single-arch 32-bit.
+ path32 = ai.nativeLibraryDir;
+ path64 = "";
}
+ if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME;
+ if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME;
+ return new String[] { path32, path64 };
}
- private static void createRelroFile(String abi) {
+ private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
+ final String abi =
+ is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+
+ // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
+ Runnable crashHandler = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
+ getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
+ }
+ }
+ };
+
try {
- Process.start("android.webkit.WebViewFactory$RelroFileCreator",
- "WebViewLoader-" + abi,
- Process.SHARED_RELRO_UID,
- Process.SHARED_RELRO_UID,
- null,
- 0, // TODO(torne): do we need to set debug flags?
- Zygote.MOUNT_EXTERNAL_NONE,
- Build.VERSION.SDK_INT,
- null,
- abi,
- null);
- } catch (Throwable e) {
+ if (nativeLibraryPaths == null
+ || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
+ throw new IllegalArgumentException(
+ "Native library paths to the WebView RelRo process must not be null!");
+ }
+ int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
+ RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
+ Process.SHARED_RELRO_UID, crashHandler);
+ if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
+ } catch (Throwable t) {
// Log and discard errors as we must not crash the system server.
- Log.e(LOGTAG, "error starting relro file creator for abi " + abi, e);
+ Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
+ crashHandler.run();
}
}
private static class RelroFileCreator {
// Called in an unprivileged child process to create the relro file.
public static void main(String[] args) {
- if (!sAddressSpaceReserved) {
- Log.e(LOGTAG, "can't create relro file; address space not reserved");
- return;
- }
- boolean result = nativeCreateRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
- CHROMIUM_WEBVIEW_NATIVE_LIB_64,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (!result) {
- Log.e(LOGTAG, "failed to create relro file");
- } else if (DEBUG) {
- Log.v(LOGTAG, "created relro file");
- }
- try {
- getUpdateService().notifyRelroCreationCompleted(VMRuntime.getRuntime().is64Bit(),
- result);
- } catch (RemoteException e) {
- Log.e(LOGTAG, "error notifying update service", e);
- }
+ boolean result = false;
+ boolean is64Bit = VMRuntime.getRuntime().is64Bit();
+ try{
+ if (args.length != 2 || args[0] == null || args[1] == null) {
+ Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
+ return;
+ }
+ Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
+ " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
+ if (!sAddressSpaceReserved) {
+ Log.e(LOGTAG, "can't create relro file; address space not reserved");
+ return;
+ }
+ result = nativeCreateRelroFile(args[0] /* path32 */,
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ if (result && DEBUG) Log.v(LOGTAG, "created relro file");
+ } finally {
+ // We must do our best to always notify the update service, even if something fails.
+ try {
+ getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "error notifying update service", e);
+ }
+
+ if (!result) Log.e(LOGTAG, "failed to create relro file");
- // Must explicitly exit or else this process will just sit around after we return.
- System.exit(0);
+ // Must explicitly exit or else this process will just sit around after we return.
+ System.exit(0);
+ }
}
}
@@ -203,14 +337,19 @@ public final class WebViewFactory {
return;
}
- boolean result = nativeLoadWithRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
- CHROMIUM_WEBVIEW_NATIVE_LIB_64,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (!result) {
- Log.w(LOGTAG, "failed to load with relro file, proceeding without");
- } else if (DEBUG) {
- Log.v(LOGTAG, "loaded with relro file");
+ try {
+ String[] args = getWebViewNativeLibraryPaths();
+ boolean result = nativeLoadWithRelroFile(args[0] /* path32 */,
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ if (!result) {
+ Log.w(LOGTAG, "failed to load with relro file, proceeding without");
+ } else if (DEBUG) {
+ Log.v(LOGTAG, "loaded with relro file");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
}
}
@@ -218,7 +357,7 @@ public final class WebViewFactory {
return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
}
- private static native boolean nativeReserveAddressSpace(String lib32, String lib64);
+ private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
String relro32, String relro64);
private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index dca9921..7db70ba 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -16,12 +16,18 @@
package com.android.internal.util;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
+import android.net.Uri;
+import android.util.Base64;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -1415,6 +1421,20 @@ public class XmlUtils {
out.attribute(null, name, Long.toString(value));
}
+ public static float readFloatAttribute(XmlPullParser in, String name) throws IOException {
+ final String value = in.getAttributeValue(null, name);
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
+ }
+ }
+
+ public static void writeFloatAttribute(XmlSerializer out, String name, float value)
+ throws IOException {
+ out.attribute(null, name, Float.toString(value));
+ }
+
public static boolean readBooleanAttribute(XmlPullParser in, String name) {
final String value = in.getAttributeValue(null, name);
return Boolean.parseBoolean(value);
@@ -1425,6 +1445,63 @@ public class XmlUtils {
out.attribute(null, name, Boolean.toString(value));
}
+ public static Uri readUriAttribute(XmlPullParser in, String name) {
+ final String value = in.getAttributeValue(null, name);
+ return (value != null) ? Uri.parse(value) : null;
+ }
+
+ public static void writeUriAttribute(XmlSerializer out, String name, Uri value)
+ throws IOException {
+ if (value != null) {
+ out.attribute(null, name, value.toString());
+ }
+ }
+
+ public static String readStringAttribute(XmlPullParser in, String name) {
+ return in.getAttributeValue(null, name);
+ }
+
+ public static void writeStringAttribute(XmlSerializer out, String name, String value)
+ throws IOException {
+ if (value != null) {
+ out.attribute(null, name, value);
+ }
+ }
+
+ public static byte[] readByteArrayAttribute(XmlPullParser in, String name) {
+ final String value = in.getAttributeValue(null, name);
+ if (value != null) {
+ return Base64.decode(value, Base64.DEFAULT);
+ } else {
+ return null;
+ }
+ }
+
+ public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)
+ throws IOException {
+ if (value != null) {
+ out.attribute(null, name, Base64.encodeToString(value, Base64.DEFAULT));
+ }
+ }
+
+ public static Bitmap readBitmapAttribute(XmlPullParser in, String name) {
+ final byte[] value = readByteArrayAttribute(in, name);
+ if (value != null) {
+ return BitmapFactory.decodeByteArray(value, 0, value.length);
+ } else {
+ return null;
+ }
+ }
+
+ public static void writeBitmapAttribute(XmlSerializer out, String name, Bitmap value)
+ throws IOException {
+ if (value != null) {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ value.compress(CompressFormat.PNG, 90, os);
+ writeByteArrayAttribute(out, name, os.toByteArray());
+ }
+ }
+
/** @hide */
public interface WriteMapCallback {
/**
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 790b611..9e24844 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -16,10 +16,12 @@
package com.android.internal.widget;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Outline;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ActionMode;
@@ -324,18 +326,36 @@ public class ActionBarContainer extends FrameLayout {
* projection surfaces.
*/
private class ActionBarBackgroundDrawable extends Drawable {
- @Override
- public void draw(Canvas canvas) {
+ private Drawable getDrawable() {
if (mIsSplit) {
- if (mSplitBackground != null) mSplitBackground.draw(canvas);
+ if (mSplitBackground != null) {
+ return mSplitBackground;
+ }
} else {
if (mBackground != null) {
- mBackground.draw(canvas);
+ return mBackground;
}
if (mStackedBackground != null && mIsStacked) {
- mStackedBackground.draw(canvas);
+ return mStackedBackground;
}
}
+ return null;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ final Drawable drawable = getDrawable();
+ if (drawable != null) {
+ drawable.draw(canvas);
+ }
+ }
+
+ @Override
+ public void getOutline(@NonNull Outline outline) {
+ final Drawable drawable = getDrawable();
+ if (drawable != null) {
+ drawable.getOutline(outline);
+ }
}
@Override