Merge "Fix permission issue on channel" into jb-mr1-dev
diff --git a/Android.mk b/Android.mk
index c2331f2..0665e60 100644
--- a/Android.mk
+++ b/Android.mk
@@ -237,9 +237,6 @@
LOCAL_MODULE := framework
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_NO_EMMA_INSTRUMENT := true
-LOCAL_NO_EMMA_COMPILE := true
-
# List of classes and interfaces which should be loaded by the Zygote.
LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes
@@ -725,9 +722,6 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ext
-LOCAL_NO_EMMA_INSTRUMENT := true
-LOCAL_NO_EMMA_COMPILE := true
-
LOCAL_DX_FLAGS := --core-library
include $(BUILD_JAVA_LIBRARY)
diff --git a/api/current.txt b/api/current.txt
index e1d07e2..b435ad0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6293,6 +6293,7 @@
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_HAS_CODE = 4; // 0x4
+ field public static final int FLAG_INSTALLED = 8388608; // 0x800000
field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
field public static final int FLAG_PERSISTENT = 8; // 0x8
@@ -6474,6 +6475,7 @@
method public abstract int checkSignatures(int, int);
method public abstract void clearPackagePreferredActivities(java.lang.String);
method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
+ method public abstract void extendVerificationTimeout(int, int, long);
method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -6592,6 +6594,7 @@
field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -6627,6 +6630,17 @@
field public java.lang.String packageName;
}
+ public class PackageUserState {
+ ctor public PackageUserState();
+ ctor public PackageUserState(android.content.pm.PackageUserState);
+ field public java.util.HashSet disabledComponents;
+ field public int enabled;
+ field public java.util.HashSet enabledComponents;
+ field public boolean installed;
+ field public boolean notLaunched;
+ field public boolean stopped;
+ }
+
public class PathPermission extends android.os.PatternMatcher {
ctor public PathPermission(java.lang.String, int, java.lang.String, java.lang.String);
ctor public PathPermission(android.os.Parcel);
@@ -11475,9 +11489,13 @@
method public void setWakeMode(android.content.Context, int);
method public void start() throws java.lang.IllegalStateException;
method public void stop() throws java.lang.IllegalStateException;
+ field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14
+ field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11
field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8
field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
+ field public static final int MEDIA_ERROR_TIMED_OUT = -110; // 0xffffff92
field public static final int MEDIA_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int MEDIA_ERROR_UNSUPPORTED = -1010; // 0xfffffc0e
field public static final int MEDIA_INFO_BAD_INTERLEAVING = 800; // 0x320
field public static final int MEDIA_INFO_BUFFERING_END = 702; // 0x2be
field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd
@@ -19988,6 +20006,10 @@
package android.security {
+ public class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+ ctor public AndroidKeyPairGeneratorSpec(android.content.Context, java.lang.String, javax.security.auth.x500.X500Principal, java.math.BigInteger, java.util.Date, java.util.Date);
+ }
+
public final class KeyChain {
ctor public KeyChain();
method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
@@ -20051,6 +20073,7 @@
method public void setContentView(android.view.View);
method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void setInteractive(boolean);
+ field public static final java.lang.String METADATA_NAME_CONFIG_ACTIVITY = "android.service.dreams.config_activity";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.Dream";
}
@@ -21309,6 +21332,7 @@
method public int checkSignatures(int, int);
method public void clearPackagePreferredActivities(java.lang.String);
method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
+ method public void extendVerificationTimeout(int, int, long);
method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -22909,6 +22933,7 @@
method public static float exp(float);
method public static float floor(float);
method public static float hypot(float, float);
+ method public static float pow(float, float);
method public static float sin(float);
method public static float sqrt(float);
}
@@ -26919,6 +26944,7 @@
method public synchronized int getDefaultFixedFontSize();
method public synchronized int getDefaultFontSize();
method public synchronized java.lang.String getDefaultTextEncodingName();
+ method public static java.lang.String getDefaultUserAgent(android.content.Context);
method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
method public boolean getDisplayZoomControls();
method public synchronized boolean getDomStorageEnabled();
@@ -26949,7 +26975,6 @@
method public synchronized boolean getUseWideViewPort();
method public deprecated synchronized int getUserAgent();
method public synchronized java.lang.String getUserAgentString();
- method public static java.lang.String getDefaultUserAgent(android.content.Context);
method public void setAllowContentAccess(boolean);
method public void setAllowFileAccess(boolean);
method public abstract void setAllowFileAccessFromFileURLs(boolean);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index a79eb14..47d6a02 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -393,7 +393,7 @@
private void runStartService() throws Exception {
Intent intent = makeIntent();
System.out.println("Starting service: " + intent);
- ComponentName cn = mAm.startService(null, intent, intent.getType());
+ ComponentName cn = mAm.startService(null, intent, intent.getType(), 0);
if (cn == null) {
System.err.println("Error: Not found; no service started.");
}
@@ -1344,6 +1344,7 @@
" am display-density [reset|DENSITY]\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
+ " am switch-user <USER_ID>\n" +
"\n" +
"am start: start an Activity. Options are:\n" +
" -D: enable debugging\n" +
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index c16e6fb..a52f74a 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -194,6 +194,11 @@
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
return -errno;
}
+ if (chmod(pkgdir, 0751) < 0) {
+ ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(pkgdir);
+ return -errno;
+ }
if (chown(pkgdir, uid, uid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 7108d68..d51004a 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -384,6 +384,11 @@
// Introducing multi-user, so migrate /data/media contents into /data/media/0
ALOGD("Migrating /data/media for multi-user");
+ // Ensure /data/media
+ if (ensure_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+ goto fail;
+ }
+
// /data/media.tmp
char media_tmp_dir[PATH_MAX];
snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b34fd05..8cc4e69 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -776,7 +776,7 @@
}
private void runInstall() {
- int installFlags = 0;
+ int installFlags = PackageManager.INSTALL_ALL_USERS;
String installerPackageName = null;
String opt;
@@ -811,6 +811,8 @@
} else if (opt.equals("-f")) {
// Override if -s option is specified.
installFlags |= PackageManager.INSTALL_INTERNAL;
+ } else if (opt.equals("-d")) {
+ installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
} else if (opt.equals("--algo")) {
algo = nextOptionData();
if (algo == null) {
@@ -1105,7 +1107,7 @@
String opt = nextOption();
if (opt != null && opt.equals("-k")) {
- unInstallFlags = PackageManager.DONT_DELETE_DATA;
+ unInstallFlags = PackageManager.DELETE_KEEP_DATA;
}
String pkg = nextArg();
@@ -1473,21 +1475,24 @@
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
System.err.println(" pm list features");
System.err.println(" pm list libraries");
+ System.err.println(" pm list users");
System.err.println(" pm path PACKAGE");
System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
System.err.println(" [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
System.err.println(" [--originating-uri <URI>] [--referrer <URI>] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
System.err.println(" pm clear PACKAGE");
- System.err.println(" pm enable PACKAGE_OR_COMPONENT");
- System.err.println(" pm disable PACKAGE_OR_COMPONENT");
- System.err.println(" pm disable-user PACKAGE_OR_COMPONENT");
+ System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
+ System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
+ System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm grant PACKAGE PERMISSION");
System.err.println(" pm revoke PACKAGE PERMISSION");
System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
System.err.println(" pm trim-caches DESIRED_FREE_SPACE");
+ System.err.println(" pm create-user USER_NAME");
+ System.err.println(" pm remove-user USER_ID");
System.err.println("");
System.err.println("pm list packages: prints all packages, optionally only");
System.err.println(" those whose package name contains the text in FILTER. Options:");
@@ -1525,6 +1530,7 @@
System.err.println(" -i: specify the installer package name.");
System.err.println(" -s: install package on sdcard.");
System.err.println(" -f: install package on internal flash.");
+ System.err.println(" -d: allow version code downgrade.");
System.err.println("");
System.err.println("pm uninstall: removes a package from the system. Options:");
System.err.println(" -k: keep the data and cache directories around after package removal.");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 395a79c..d5580b7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -48,6 +48,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.os.UserHandle;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -3384,6 +3385,31 @@
}
/**
+ * @hide Implement to provide correct calling token.
+ */
+ public void startActivityAsUser(Intent intent, UserHandle user) {
+ startActivityAsUser(intent, null, user);
+ }
+
+ /**
+ * @hide Implement to provide correct calling token.
+ */
+ public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+ if (mParent != null) {
+ throw new RuntimeException("Called be called from a child");
+ }
+ Instrumentation.ActivityResult ar =
+ mInstrumentation.execStartActivity(
+ this, mMainThread.getApplicationThread(), mToken, this,
+ intent, -1, options, user);
+ if (ar != null) {
+ mMainThread.sendActivityResult(
+ mToken, mEmbeddedID, -1, ar.getResultCode(),
+ ar.getResultData());
+ }
+ }
+
+ /**
* Same as calling {@link #startIntentSenderForResult(IntentSender, int,
* Intent, int, int, int, Bundle)} with no options.
*
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3197a63..adc9434 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -697,7 +697,8 @@
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
- ComponentName cn = startService(app, service, resolvedType);
+ int userId = data.readInt();
+ ComponentName cn = startService(app, service, resolvedType, userId);
reply.writeNoException();
ComponentName.writeToParcel(cn, reply);
return true;
@@ -709,7 +710,8 @@
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
- int res = stopService(app, service, resolvedType);
+ int userId = data.readInt();
+ int res = stopService(app, service, resolvedType, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -2523,7 +2525,7 @@
}
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType) throws RemoteException
+ String resolvedType, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2531,6 +2533,7 @@
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
+ data.writeInt(userId);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
ComponentName res = ComponentName.readFromParcel(reply);
@@ -2539,7 +2542,7 @@
return res;
}
public int stopService(IApplicationThread caller, Intent service,
- String resolvedType) throws RemoteException
+ String resolvedType, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2547,6 +2550,7 @@
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
+ data.writeInt(userId);
mRemote.transact(STOP_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4740e53c..b8e16c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4070,10 +4070,14 @@
if (!Process.isIsolated()) {
final File cacheDir = appContext.getCacheDir();
- // Provide a usable directory for temporary files
- System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-
- setupGraphicsSupport(data.info, cacheDir);
+ if (cacheDir != null) {
+ // Provide a usable directory for temporary files
+ System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
+
+ setupGraphicsSupport(data.info, cacheDir);
+ } else {
+ Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
+ }
}
/**
* For system applications on userdebug/eng builds, log stack
@@ -4817,13 +4821,14 @@
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
- if (sMainThreadHandler == null) {
- sMainThreadHandler = new Handler();
- }
ActivityThread thread = new ActivityThread();
thread.attach(false);
+ if (sMainThreadHandler == null) {
+ sMainThreadHandler = thread.getHandler();
+ }
+
AsyncTask.init();
if (false) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 86ee8a0..0f10c4f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -45,6 +45,7 @@
import android.content.pm.UserInfo;
import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -997,6 +998,21 @@
}
@Override
+ public int installExistingPackage(String packageName)
+ throws NameNotFoundException {
+ try {
+ int res = mPM.installExistingPackage(packageName);
+ if (res == INSTALL_FAILED_INVALID_URI) {
+ throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+ }
+ return res;
+ } catch (RemoteException e) {
+ // Should never happen!
+ throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+ }
+ }
+
+ @Override
public void verifyPendingInstall(int id, int response) {
try {
mPM.verifyPendingInstall(id, response);
@@ -1006,6 +1022,16 @@
}
@Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ try {
+ mPM.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
public void setInstallerPackageName(String targetPackage,
String installerPackageName) {
try {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0543f05..32086d7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -769,7 +769,7 @@
}
if (!mCacheDir.exists()) {
if(!mCacheDir.mkdirs()) {
- Log.w(TAG, "Unable to create cache directory");
+ Log.w(TAG, "Unable to create cache directory " + mCacheDir.getAbsolutePath());
return null;
}
FileUtils.setPermissions(
@@ -909,14 +909,7 @@
/** @hide */
@Override
public void startActivityAsUser(Intent intent, UserHandle user) {
- try {
- ActivityManagerNative.getDefault().startActivityAsUser(
- mMainThread.getApplicationThread(), intent,
- intent.resolveTypeIfNeeded(getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, null,
- user.getIdentifier());
- } catch (RemoteException re) {
- }
+ startActivityAsUser(intent, null, user);
}
@Override
@@ -1227,11 +1220,21 @@
@Override
public ComponentName startService(Intent service) {
+ return startServiceAsUser(service, Process.myUserHandle());
+ }
+
+ @Override
+ public boolean stopService(Intent service) {
+ return stopServiceAsUser(service, Process.myUserHandle());
+ }
+
+ @Override
+ public ComponentName startServiceAsUser(Intent service, UserHandle user) {
try {
service.setAllowFds(false);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
- service.resolveTypeIfNeeded(getContentResolver()));
+ service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
if (cn != null && cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
@@ -1244,12 +1247,12 @@
}
@Override
- public boolean stopService(Intent service) {
+ public boolean stopServiceAsUser(Intent service, UserHandle user) {
try {
service.setAllowFds(false);
int res = ActivityManagerNative.getDefault().stopService(
mMainThread.getApplicationThread(), service,
- service.resolveTypeIfNeeded(getContentResolver()));
+ service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to stop service " + service);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a6d1995..c3e911e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -133,9 +133,9 @@
public PendingIntent getRunningServiceControlPanel(ComponentName service)
throws RemoteException;
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType) throws RemoteException;
+ String resolvedType, int userId) throws RemoteException;
public int stopService(IApplicationThread caller, Intent service,
- String resolvedType) throws RemoteException;
+ String resolvedType, int userId) throws RemoteException;
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) throws RemoteException;
public void setServiceForeground(ComponentName className, IBinder token,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index cad4b01..ee4e964 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -33,6 +33,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.IWindowManager;
@@ -1518,6 +1519,66 @@
return null;
}
+ /**
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * but for starting as a particular user.
+ *
+ * @param who The Context from which the activity is being started.
+ * @param contextThread The main thread of the Context from which the activity
+ * is being started.
+ * @param token Internal token identifying to the system who is starting
+ * the activity; may be null.
+ * @param target Which fragment is performing the start (and thus receiving
+ * any result).
+ * @param intent The actual Intent to start.
+ * @param requestCode Identifier for this request's result; less than zero
+ * if the caller is not expecting a result.
+ *
+ * @return To force the return of a particular result, return an
+ * ActivityResult object containing the desired data; otherwise
+ * return null. The default implementation always returns null.
+ *
+ * @throws android.content.ActivityNotFoundException
+ *
+ * @see Activity#startActivity(Intent)
+ * @see Activity#startActivityForResult(Intent, int)
+ * @see Activity#startActivityFromChild
+ *
+ * {@hide}
+ */
+ public ActivityResult execStartActivity(
+ Context who, IBinder contextThread, IBinder token, Activity target,
+ Intent intent, int requestCode, Bundle options, UserHandle user) {
+ IApplicationThread whoThread = (IApplicationThread) contextThread;
+ if (mActivityMonitors != null) {
+ synchronized (mSync) {
+ final int N = mActivityMonitors.size();
+ for (int i=0; i<N; i++) {
+ final ActivityMonitor am = mActivityMonitors.get(i);
+ if (am.match(who, null, intent)) {
+ am.mHits++;
+ if (am.isBlocking()) {
+ return requestCode >= 0 ? am.getResult() : null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ try {
+ intent.setAllowFds(false);
+ intent.migrateExtraStreamToClipData();
+ int result = ActivityManagerNative.getDefault()
+ .startActivityAsUser(whoThread, intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()),
+ token, target != null ? target.mEmbeddedID : null,
+ requestCode, 0, null, null, options, user.getIdentifier());
+ checkStartActivityResult(result, intent);
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
/*package*/ final void init(ActivityThread thread,
Context instrContext, Context appContext, ComponentName component,
IInstrumentationWatcher watcher) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1460bf5..dc6d93f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1414,6 +1414,16 @@
public abstract boolean stopService(Intent service);
/**
+ * @hide like {@link #startService(Intent)} but for a specific user.
+ */
+ public abstract ComponentName startServiceAsUser(Intent service, UserHandle user);
+
+ /**
+ * @hide like {@link #stopService(Intent)} but for a specific user.
+ */
+ public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
+
+ /**
* Connect to an application service, creating it if needed. This defines
* a dependency between your application and the service. The given
* <var>conn</var> will receive the service object when it is created and be
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3a13725..4bbe44e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -410,6 +410,18 @@
return mBase.stopService(name);
}
+ /** @hide */
+ @Override
+ public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+ return mBase.startServiceAsUser(service, user);
+ }
+
+ /** @hide */
+ @Override
+ public boolean stopServiceAsUser(Intent name, UserHandle user) {
+ return mBase.stopServiceAsUser(name, user);
+ }
+
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index cbabc7c..1a82d58 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -302,6 +302,12 @@
public static final int FLAG_SUPPORTS_RTL = 1<<22;
/**
+ * Value for {@link #flags}: true if the application is currently
+ * installed for the calling user.
+ */
+ public static final int FLAG_INSTALLED = 1<<23;
+
+ /**
* Value for {@link #flags}: Set to true if the application has been
* installed using the forward lock option.
*
@@ -334,7 +340,8 @@
* {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
* {@link #FLAG_RESIZEABLE_FOR_SCREENS},
- * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE}
+ * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
+ * {@link #FLAG_INSTALLED}.
*/
public int flags = 0;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 3f4b994..0e1fe3e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -32,6 +32,7 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ManifestDigest;
+import android.content.pm.PackageCleanItem;
import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.PermissionGroupInfo;
@@ -351,7 +352,7 @@
*/
void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
- String nextPackageToClean(String lastPackage);
+ PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
void movePackage(String packageName, IPackageMoveObserver observer, int flags);
@@ -369,7 +370,10 @@
in VerificationParams verificationParams,
in ContainerEncryptionParams encryptionParams);
+ int installExistingPackage(String packageName);
+
void verifyPendingInstall(int id, int verificationCode);
+ void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
VerifierDeviceIdentity getVerifierDeviceIdentity();
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
index f5e72e0..75505bc 100644
--- a/core/java/android/content/pm/ManifestDigest.java
+++ b/core/java/android/content/pm/ManifestDigest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 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.content.pm;
import android.os.Parcel;
diff --git a/core/java/android/content/pm/PackageCleanItem.aidl b/core/java/android/content/pm/PackageCleanItem.aidl
new file mode 100644
index 0000000..9bb203e
--- /dev/null
+++ b/core/java/android/content/pm/PackageCleanItem.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2012, 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.content.pm;
+
+parcelable PackageCleanItem;
diff --git a/core/java/android/content/pm/PackageCleanItem.java b/core/java/android/content/pm/PackageCleanItem.java
new file mode 100644
index 0000000..eea3b9c
--- /dev/null
+++ b/core/java/android/content/pm/PackageCleanItem.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 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.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class PackageCleanItem {
+ public final String packageName;
+ public final boolean andCode;
+
+ public PackageCleanItem(String packageName, boolean andCode) {
+ this.packageName = packageName;
+ this.andCode = andCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ try {
+ if (obj != null) {
+ PackageCleanItem other = (PackageCleanItem)obj;
+ return packageName.equals(other.packageName) && andCode == other.andCode;
+ }
+ } catch (ClassCastException e) {
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + packageName.hashCode();
+ result = 31 * result + (andCode ? 1 : 0);
+ return result;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(packageName);
+ dest.writeInt(andCode ? 1 : 0);
+ }
+
+ public static final Parcelable.Creator<PackageCleanItem> CREATOR
+ = new Parcelable.Creator<PackageCleanItem>() {
+ public PackageCleanItem createFromParcel(Parcel source) {
+ return new PackageCleanItem(source);
+ }
+
+ public PackageCleanItem[] newArray(int size) {
+ return new PackageCleanItem[size];
+ }
+ };
+
+ private PackageCleanItem(Parcel source) {
+ packageName = source.readString();
+ andCode = source.readInt() != 0;
+ }
+}
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 9625944..a1566da 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -32,6 +32,11 @@
public String packageName;
/**
+ * The android:versionCode of the package.
+ */
+ public int versionCode;
+
+ /**
* Specifies the recommended install location. Can be one of
* {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage
* {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media
@@ -58,6 +63,7 @@
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(packageName);
+ dest.writeInt(versionCode);
dest.writeInt(recommendedInstallLocation);
dest.writeInt(installLocation);
@@ -82,6 +88,7 @@
private PackageInfoLite(Parcel source) {
packageName = source.readString();
+ versionCode = source.readInt();
recommendedInstallLocation = source.readInt();
installLocation = source.readInt();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0461dd1..0d99d3f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -310,6 +310,23 @@
public static final int INSTALL_FROM_ADB = 0x00000020;
/**
+ * Flag parameter for {@link #installPackage} to indicate that this install
+ * should immediately be visible to all users.
+ *
+ * @hide
+ */
+ public static final int INSTALL_ALL_USERS = 0x00000040;
+
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that it is okay
+ * to install an update to an app where the newly installed app has a lower
+ * version code than the currently installed app.
+ *
+ * @hide
+ */
+ public static final int INSTALL_ALLOW_DOWNGRADE = 0x00000080;
+
+ /**
* Flag parameter for
* {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
* that you don't want to kill the app containing the component. Be careful when you set this
@@ -529,6 +546,14 @@
public static final int INSTALL_FAILED_UID_CHANGED = -24;
/**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package has an older version code than the currently installed package.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;
+
+ /**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was given a path that is not a file, or does not end with the expected
@@ -625,7 +650,15 @@
*
* @hide
*/
- public static final int DONT_DELETE_DATA = 0x00000001;
+ public static final int DELETE_KEEP_DATA = 0x00000001;
+
+ /**
+ * Flag parameter for {@link #deletePackage} to indicate that you want the
+ * package deleted for all users.
+ *
+ * @hide
+ */
+ public static final int DELETE_ALL_USERS = 0x00000002;
/**
* Return code for when package deletion succeeds. This is passed to the
@@ -762,6 +795,14 @@
public static final int VERIFICATION_REJECT = -1;
/**
+ * Can be used as the {@code millisecondsToDelay} argument for
+ * {@link PackageManager#extendVerificationTimeout}. This is the
+ * maximum time {@code PackageManager} waits for the verification
+ * agent to return (in milliseconds).
+ */
+ public static final long MAXIMUM_VERIFICATION_TIMEOUT = 60*60*1000;
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device's
* audio pipeline is low-latency, more suitable for audio applications sensitive to delays or
* lag in sound input or output.
@@ -2167,8 +2208,8 @@
if ((flags & GET_SIGNATURES) != 0) {
packageParser.collectCertificates(pkg, 0);
}
- return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, false,
- COMPONENT_ENABLED_STATE_DEFAULT);
+ PackageUserState state = new PackageUserState();
+ return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
}
/**
@@ -2259,6 +2300,14 @@
ContainerEncryptionParams encryptionParams);
/**
+ * If there is already an application with the given package name installed
+ * on the system for other users, also install it for the calling user.
+ * @hide
+ */
+ public abstract int installExistingPackage(String packageName)
+ throws NameNotFoundException;
+
+ /**
* Allows a package listening to the
* {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification
* broadcast} to respond to the package manager. The response must include
@@ -2274,6 +2323,33 @@
public abstract void verifyPendingInstall(int id, int verificationCode);
/**
+ * Allows a package listening to the
+ * {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification
+ * broadcast} to extend the default timeout for a response and declare what
+ * action to perform after the timeout occurs. The response must include
+ * the {@code verificationCodeAtTimeout} which is one of
+ * {@link PackageManager#VERIFICATION_ALLOW} or
+ * {@link PackageManager#VERIFICATION_REJECT}.
+ *
+ * This method may only be called once per package id. Additional calls
+ * will have no effect.
+ *
+ * @param id pending package identifier as passed via the
+ * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+ * @param verificationCodeAtTimeout either
+ * {@link PackageManager#VERIFICATION_ALLOW} or
+ * {@link PackageManager#VERIFICATION_REJECT}.
+ * @param millisecondsToDelay the amount of time requested for the timeout.
+ * Must be positive and less than
+ * {@link PackageManager#MAXIMUM_VERIFICATION_TIMEOUT}.
+ *
+ * @throws IllegalArgumentException if {@code millisecondsToDelay} is out
+ * of bounds or {@code verificationCodeAtTimeout} is unknown.
+ */
+ public abstract void extendVerificationTimeout(int id,
+ int verificationCodeAtTimeout, long millisecondsToDelay);
+
+ /**
* Change the installer associated with a given package. There are limitations
* on how the installer package can be changed; in particular:
* <ul>
@@ -2302,7 +2378,8 @@
* @param observer An observer callback to get notified when the package deletion is
* complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
- * @param flags - possible values: {@link #DONT_DELETE_DATA}
+ * @param flags - possible values: {@link #DELETE_KEEP_DATA},
+ * {@link #DELETE_ALL_USERS}.
*
* @hide
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ac75040..237f5c5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -203,11 +203,14 @@
*/
public static class PackageLite {
public final String packageName;
+ public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
- public PackageLite(String packageName, int installLocation, List<VerifierInfo> verifiers) {
+ public PackageLite(String packageName, int versionCode,
+ int installLocation, List<VerifierInfo> verifiers) {
this.packageName = packageName;
+ this.versionCode = versionCode;
this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
}
@@ -243,14 +246,15 @@
return name.endsWith(".apk");
}
+ /*
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
HashSet<String> grantedPermissions) {
-
+ PackageUserState state = new PackageUserState();
return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
- grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
- UserHandle.getCallingUserId());
+ grantedPermissions, state, UserHandle.getCallingUserId());
}
+ */
/**
* Generate and return the {@link PackageInfo} for a parsed package.
@@ -260,23 +264,30 @@
*/
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
- HashSet<String> grantedPermissions, boolean stopped, int enabledState) {
+ HashSet<String> grantedPermissions, PackageUserState state) {
return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
- grantedPermissions, stopped, enabledState, UserHandle.getCallingUserId());
+ grantedPermissions, state, UserHandle.getCallingUserId());
+ }
+
+ private static boolean checkUseInstalled(int flags, PackageUserState state) {
+ return state.installed || ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0);
}
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
- HashSet<String> grantedPermissions, boolean stopped, int enabledState, int userId) {
+ HashSet<String> grantedPermissions, PackageUserState state, int userId) {
+ if (!checkUseInstalled(flags, state)) {
+ return null;
+ }
PackageInfo pi = new PackageInfo();
pi.packageName = p.packageName;
pi.versionCode = p.mVersionCode;
pi.versionName = p.mVersionName;
pi.sharedUserId = p.mSharedUserId;
pi.sharedUserLabel = p.mSharedUserLabel;
- pi.applicationInfo = generateApplicationInfo(p, flags, stopped, enabledState, userId);
+ pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
pi.installLocation = p.installLocation;
pi.firstInstallTime = firstInstallTime;
pi.lastUpdateTime = lastUpdateTime;
@@ -312,7 +323,7 @@
if (activity.info.enabled
|| (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
- stopped, enabledState, userId);
+ state, userId);
}
}
}
@@ -334,7 +345,7 @@
if (activity.info.enabled
|| (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags,
- stopped, enabledState, userId);
+ state, userId);
}
}
}
@@ -355,8 +366,8 @@
final Service service = p.services.get(i);
if (service.info.enabled
|| (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
- pi.services[j++] = generateServiceInfo(p.services.get(i), flags, stopped,
- enabledState, userId);
+ pi.services[j++] = generateServiceInfo(p.services.get(i), flags,
+ state, userId);
}
}
}
@@ -377,8 +388,8 @@
final Provider provider = p.providers.get(i);
if (provider.info.enabled
|| (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
- pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, stopped,
- enabledState, userId);
+ pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags,
+ state, userId);
}
}
}
@@ -840,11 +851,19 @@
return null;
}
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
+ int versionCode = 0;
+ int numFound = 0;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
String attr = attrs.getAttributeName(i);
if (attr.equals("installLocation")) {
installLocation = attrs.getAttributeIntValue(i,
PARSE_DEFAULT_INSTALL_LOCATION);
+ numFound++;
+ } else if (attr.equals("versionCode")) {
+ versionCode = attrs.getAttributeIntValue(i, 0);
+ numFound++;
+ }
+ if (numFound >= 2) {
break;
}
}
@@ -867,7 +886,7 @@
}
}
- return new PackageLite(pkgName.intern(), installLocation, verifiers);
+ return new PackageLite(pkgName.intern(), versionCode, installLocation, verifiers);
}
/**
@@ -3458,13 +3477,25 @@
}
}
- private static boolean copyNeeded(int flags, Package p, int enabledState, Bundle metaData) {
- if (enabledState != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
- boolean enabled = enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ private static boolean copyNeeded(int flags, Package p,
+ PackageUserState state, Bundle metaData, int userId) {
+ if (userId != 0) {
+ // We always need to copy for other users, since we need
+ // to fix up the uid.
+ return true;
+ }
+ if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+ boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
if (p.applicationInfo.enabled != enabled) {
return true;
}
}
+ if (!state.installed) {
+ return true;
+ }
+ if (state.stopped) {
+ return true;
+ }
if ((flags & PackageManager.GET_META_DATA) != 0
&& (metaData != null || p.mAppMetaData != null)) {
return true;
@@ -3476,32 +3507,34 @@
return false;
}
- public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped,
- int enabledState) {
- return generateApplicationInfo(p, flags, stopped, enabledState, UserHandle.getCallingUserId());
+ public static ApplicationInfo generateApplicationInfo(Package p, int flags,
+ PackageUserState state) {
+ return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
- boolean stopped, int enabledState, int userId) {
+ PackageUserState state, int userId) {
if (p == null) return null;
- if (!copyNeeded(flags, p, enabledState, null) && userId == 0) {
+ if (!checkUseInstalled(flags, state)) {
+ return null;
+ }
+ if (!copyNeeded(flags, p, state, null, userId)) {
// CompatibilityMode is global state. It's safe to modify the instance
// of the package.
if (!sCompatibilityModeEnabled) {
p.applicationInfo.disableCompatibilityMode();
}
- if (stopped) {
- p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
- } else {
- p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
- }
- if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ // Make sure we report as installed. Also safe to do, since the
+ // default state should be installed (we will always copy if we
+ // need to report it is not installed).
+ p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+ if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
p.applicationInfo.enabled = true;
- } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
p.applicationInfo.enabled = false;
}
- p.applicationInfo.enabledSetting = enabledState;
+ p.applicationInfo.enabledSetting = state.enabled;
return p.applicationInfo;
}
@@ -3520,18 +3553,23 @@
if (!sCompatibilityModeEnabled) {
ai.disableCompatibilityMode();
}
- if (stopped) {
+ if (state.stopped) {
ai.flags |= ApplicationInfo.FLAG_STOPPED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
}
- if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ if (state.installed) {
+ ai.flags |= ApplicationInfo.FLAG_INSTALLED;
+ } else {
+ ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+ }
+ if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
- } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
ai.enabled = false;
}
- ai.enabledSetting = enabledState;
+ ai.enabledSetting = state.enabled;
return ai;
}
@@ -3578,16 +3616,19 @@
}
}
- public static final ActivityInfo generateActivityInfo(Activity a, int flags, boolean stopped,
- int enabledState, int userId) {
+ public static final ActivityInfo generateActivityInfo(Activity a, int flags,
+ PackageUserState state, int userId) {
if (a == null) return null;
- if (!copyNeeded(flags, a.owner, enabledState, a.metaData) && userId == 0) {
+ if (!checkUseInstalled(flags, state)) {
+ return null;
+ }
+ if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
return a.info;
}
// Make shallow copies so we can store the metadata safely
ActivityInfo ai = new ActivityInfo(a.info);
ai.metaData = a.metaData;
- ai.applicationInfo = generateApplicationInfo(a.owner, flags, stopped, enabledState, userId);
+ ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
return ai;
}
@@ -3612,17 +3653,19 @@
}
}
- public static final ServiceInfo generateServiceInfo(Service s, int flags, boolean stopped,
- int enabledState, int userId) {
+ public static final ServiceInfo generateServiceInfo(Service s, int flags,
+ PackageUserState state, int userId) {
if (s == null) return null;
- if (!copyNeeded(flags, s.owner, enabledState, s.metaData)
- && userId == UserHandle.getUserId(s.info.applicationInfo.uid)) {
+ if (!checkUseInstalled(flags, state)) {
+ return null;
+ }
+ if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
return s.info;
}
// Make shallow copies so we can store the metadata safely
ServiceInfo si = new ServiceInfo(s.info);
si.metaData = s.metaData;
- si.applicationInfo = generateApplicationInfo(s.owner, flags, stopped, enabledState, userId);
+ si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
return si;
}
@@ -3655,13 +3698,15 @@
}
}
- public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped,
- int enabledState, int userId) {
+ public static final ProviderInfo generateProviderInfo(Provider p, int flags,
+ PackageUserState state, int userId) {
if (p == null) return null;
- if (!copyNeeded(flags, p.owner, enabledState, p.metaData)
+ if (!checkUseInstalled(flags, state)) {
+ return null;
+ }
+ if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
&& ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
- || p.info.uriPermissionPatterns == null)
- && userId == 0) {
+ || p.info.uriPermissionPatterns == null)) {
return p.info;
}
// Make shallow copies so we can store the metadata safely
@@ -3670,7 +3715,7 @@
if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
pi.uriPermissionPatterns = null;
}
- pi.applicationInfo = generateApplicationInfo(p.owner, flags, stopped, enabledState, userId);
+ pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
return pi;
}
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
new file mode 100644
index 0000000..1a71bfb
--- /dev/null
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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.content.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+
+import java.util.HashSet;
+
+/**
+ * Per-user state information about a package.
+ */
+public class PackageUserState {
+ public boolean stopped;
+ public boolean notLaunched;
+ public boolean installed;
+ public int enabled;
+
+ public HashSet<String> disabledComponents;
+ public HashSet<String> enabledComponents;
+
+ public PackageUserState() {
+ installed = true;
+ enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+
+ public PackageUserState(PackageUserState o) {
+ installed = o.installed;
+ stopped = o.stopped;
+ notLaunched = o.notLaunched;
+ enabled = o.enabled;
+ disabledComponents = o.disabledComponents != null
+ ? new HashSet<String>(o.disabledComponents) : null;
+ enabledComponents = o.enabledComponents != null
+ ? new HashSet<String>(o.enabledComponents) : null;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 0bc0f91..7642670 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -331,12 +331,16 @@
notifyListener(v1, true /* removed */);
}
if (changes.length() > 0) {
- Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
- serviceInfos.size() + " services:\n" + changes);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
+ serviceInfos.size() + " services:\n" + changes);
+ }
writePersistentServicesLocked();
} else {
- Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
- serviceInfos.size() + " services unchanged");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
+ serviceInfos.size() + " services unchanged");
+ }
}
mPersistentServicesFileDidNotExist = false;
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index a73115c..98d2f69 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -24,7 +24,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
-import android.util.SparseArray;
import android.view.CompatibilityInfoHolder;
import android.view.Display;
import android.view.DisplayInfo;
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
new file mode 100644
index 0000000..99bd647
--- /dev/null
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Interface to control and observe state of a specific network, hiding
+ * network-specific details from {@link ConnectivityManager}. Surfaces events
+ * through the registered {@link Handler} to enable {@link ConnectivityManager}
+ * to respond to state changes over time.
+ *
+ * @hide
+ */
+public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
+ // TODO: better document threading expectations
+ // TODO: migrate to make NetworkStateTracker abstract class
+
+ public static final String PROP_TCP_BUFFER_UNKNOWN = "net.tcp.buffersize.unknown";
+ public static final String PROP_TCP_BUFFER_WIFI = "net.tcp.buffersize.wifi";
+
+ protected Context mContext;
+ private Handler mTarget;
+
+ protected NetworkInfo mNetworkInfo;
+ protected LinkProperties mLinkProperties;
+ protected LinkCapabilities mLinkCapabilities;
+
+ private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
+ private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
+ private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
+
+ public BaseNetworkStateTracker(int networkType) {
+ mNetworkInfo = new NetworkInfo(
+ networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null);
+ mLinkProperties = new LinkProperties();
+ mLinkCapabilities = new LinkCapabilities();
+ }
+
+ @Deprecated
+ protected Handler getTargetHandler() {
+ return mTarget;
+ }
+
+ protected final void dispatchStateChanged() {
+ // TODO: include snapshot of other fields when sending
+ mTarget.obtainMessage(EVENT_STATE_CHANGED, getNetworkInfo()).sendToTarget();
+ }
+
+ protected final void dispatchConfigurationChanged() {
+ // TODO: include snapshot of other fields when sending
+ mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, getNetworkInfo()).sendToTarget();
+ }
+
+ @Override
+ public final void startMonitoring(Context context, Handler target) {
+ mContext = Preconditions.checkNotNull(context);
+ mTarget = Preconditions.checkNotNull(target);
+ startMonitoringInternal();
+ }
+
+ protected abstract void startMonitoringInternal();
+
+ @Override
+ public final NetworkInfo getNetworkInfo() {
+ return new NetworkInfo(mNetworkInfo);
+ }
+
+ @Override
+ public final LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
+ }
+
+ @Override
+ public final LinkCapabilities getLinkCapabilities() {
+ return new LinkCapabilities(mLinkCapabilities);
+ }
+
+ @Override
+ public boolean setRadio(boolean turnOn) {
+ // Base tracker doesn't handle radios
+ return true;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mNetworkInfo.isAvailable();
+ }
+
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ // Base tracker doesn't handle enabled flags
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ // Base tracker doesn't handle enabled flags
+ }
+
+ @Override
+ public boolean isPrivateDnsRouteSet() {
+ return mPrivateDnsRouteSet.get();
+ }
+
+ @Override
+ public void privateDnsRouteSet(boolean enabled) {
+ mPrivateDnsRouteSet.set(enabled);
+ }
+
+ @Override
+ public boolean isDefaultRouteSet() {
+ return mDefaultRouteSet.get();
+ }
+
+ @Override
+ public void defaultRouteSet(boolean enabled) {
+ mDefaultRouteSet.set(enabled);
+ }
+
+ @Override
+ public boolean isTeardownRequested() {
+ return mTeardownRequested.get();
+ }
+
+ @Override
+ public void setTeardownRequested(boolean isRequested) {
+ mTeardownRequested.set(isRequested);
+ }
+
+ @Override
+ public void setDependencyMet(boolean met) {
+ // Base tracker doesn't handle dependencies
+ }
+}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 92aeff2..dea25dd 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -26,6 +26,7 @@
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
/**
* Interface that answers queries about, and allows changing, the
@@ -118,7 +119,7 @@
ParcelFileDescriptor establishVpn(in VpnConfig config);
- void startLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd);
+ void startLegacyVpn(in VpnProfile profile);
LegacyVpnInfo getLegacyVpnInfo();
}
diff --git a/core/java/android/net/arp/ArpPeer.java b/core/java/android/net/arp/ArpPeer.java
index 5f68fdf..2013b11 100644
--- a/core/java/android/net/arp/ArpPeer.java
+++ b/core/java/android/net/arp/ArpPeer.java
@@ -58,9 +58,11 @@
mInterfaceName = interfaceName;
mMyAddr = myAddr;
- for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
- mMyMac[i] = (byte) Integer.parseInt(mac.substring(
- i*3, (i*3) + 2), 16);
+ if (mac != null) {
+ for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
+ mMyMac[i] = (byte) Integer.parseInt(mac.substring(
+ i*3, (i*3) + 2), 16);
+ }
}
if (myAddr instanceof Inet6Address || peer instanceof Inet6Address) {
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 7785368..4e2b5c0 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -101,37 +101,88 @@
}
/**
- * Default constructor associates this handler with the queue for the
+ * Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
- * If there isn't one, this handler won't be able to receive messages.
+ * If this thread does not have a looper, this handler won't be able to receive messages
+ * so an exception is thrown.
*/
public Handler() {
- if (FIND_POTENTIAL_LEAKS) {
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
-
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue;
- mCallback = null;
- mAsynchronous = false;
+ this(null, false);
}
/**
- * Constructor associates this handler with the queue for the
+ * Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
+ *
+ * If this thread does not have a looper, this handler won't be able to receive messages
+ * so an exception is thrown.
+ *
+ * @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Callback callback) {
+ this(callback, false);
+ }
+
+ /**
+ * Use the provided {@link Looper} instead of the default one.
+ *
+ * @param looper The looper, must not be null.
+ */
+ public Handler(Looper looper) {
+ this(looper, null, false);
+ }
+
+ /**
+ * Use the provided {@link Looper} instead of the default one and take a callback
+ * interface in which to handle messages.
+ *
+ * @param looper The looper, must not be null.
+ * @param callback The callback interface in which to handle messages, or null.
+ */
+ public Handler(Looper looper, Callback callback) {
+ this(looper, callback, false);
+ }
+
+ /**
+ * Use the {@link Looper} for the current thread
+ * and set whether the handler should be asynchronous.
+ *
+ * Handlers are synchronous by default unless this constructor is used to make
+ * one that is strictly asynchronous.
+ *
+ * Asynchronous messages represent interrupts or events that do not require global ordering
+ * with represent to synchronous messages. Asynchronous messages are not subject to
+ * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
+ *
+ * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
+ * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
+ *
+ * @hide
+ */
+ public Handler(boolean async) {
+ this(null, async);
+ }
+
+ /**
+ * Use the {@link Looper} for the current thread with the specified callback interface
+ * and set whether the handler should be asynchronous.
+ *
+ * Handlers are synchronous by default unless this constructor is used to make
+ * one that is strictly asynchronous.
+ *
+ * Asynchronous messages represent interrupts or events that do not require global ordering
+ * with represent to synchronous messages. Asynchronous messages are not subject to
+ * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
+ *
+ * @param callback The callback interface in which to handle messages, or null.
+ * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
+ * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
+ *
+ * @hide
+ */
+ public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
@@ -148,32 +199,11 @@
}
mQueue = mLooper.mQueue;
mCallback = callback;
- mAsynchronous = false;
+ mAsynchronous = async;
}
/**
- * Use the provided queue instead of the default one.
- */
- public Handler(Looper looper) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = null;
- mAsynchronous = false;
- }
-
- /**
- * Use the provided queue instead of the default one and take a callback
- * interface in which to handle messages.
- */
- public Handler(Looper looper, Callback callback) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = callback;
- mAsynchronous = false;
- }
-
- /**
- * Use the provided queue instead of the default one and take a callback
+ * Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
@@ -184,6 +214,8 @@
* with represent to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
+ * @param looper The looper, must not be null.
+ * @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 20d3ec3..2179fa1 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -362,4 +362,11 @@
* Flush the DNS cache associated with the specified interface.
*/
void flushInterfaceDnsCache(String iface);
+
+ void setFirewallEnabled(boolean enabled);
+ boolean isFirewallEnabled();
+ void setFirewallInterfaceRule(String iface, boolean allow);
+ void setFirewallEgressSourceRule(String addr, boolean allow);
+ void setFirewallEgressDestRule(String addr, int port, boolean allow);
+ void setFirewallUidRule(int uid, boolean allow);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index efdbcac..a1901a5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -239,13 +239,6 @@
*/
public static final int BRIGHTNESS_OFF = 0;
- /**
- * A nominal default brightness value.
- * Use {@link #getDefaultScreenBrightnessSetting()} instead.
- * @hide
- */
- private static final int BRIGHTNESS_DEFAULT = 102;
-
// Note: Be sure to update android.os.BatteryStats and PowerManager.h
// if adding or modifying user activity event constants.
@@ -275,13 +268,6 @@
public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0;
/**
- * Special wake lock tag used for the wake lock in the Window Manager that handles the
- * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} flag.
- * @hide
- */
- public static final String KEEP_SCREEN_ON_FLAG_TAG = "KEEP_SCREEN_ON_FLAG";
-
- /**
* Go to sleep reason code: Going to sleep due by user request.
* @hide
*/
@@ -321,7 +307,7 @@
*/
public int getMinimumScreenBrightnessSetting() {
return mContext.getResources().getInteger(
- com.android.internal.R.integer.config_screenBrightnessDim);
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
}
/**
@@ -331,7 +317,8 @@
* @hide
*/
public int getMaximumScreenBrightnessSetting() {
- return BRIGHTNESS_ON;
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
}
/**
@@ -339,7 +326,8 @@
* @hide
*/
public int getDefaultScreenBrightnessSetting() {
- return BRIGHTNESS_DEFAULT;
+ return mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingDefault);
}
/**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 3513bdc..851b8df 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -582,9 +582,7 @@
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
- if (mountExternal == Zygote.MOUNT_EXTERNAL_SINGLEUSER) {
- argsForZygote.add("--mount-external-singleuser");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
+ if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
argsForZygote.add("--mount-external-multiuser");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 43cf74e..0d11ab4 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -40,6 +40,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -326,7 +327,8 @@
throws IOException {
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
- String arg = "--update_package=" + filename;
+ String arg = "--update_package=" + filename +
+ "\n--locale=" + Locale.getDefault().toString();
bootCommand(context, arg);
}
@@ -357,7 +359,7 @@
// Block until the ordered broadcast has completed.
condition.block();
- bootCommand(context, "--wipe_data");
+ bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString());
}
/**
@@ -365,7 +367,7 @@
* @throws IOException if something goes wrong.
*/
public static void rebootWipeCache(Context context) throws IOException {
- bootCommand(context, "--wipe_cache");
+ bootCommand(context, "--wipe_cache\n--locale=" + Locale.getDefault().toString());
}
/**
diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java
index db58012..f345271 100644
--- a/core/java/android/os/SystemService.java
+++ b/core/java/android/os/SystemService.java
@@ -16,6 +16,8 @@
package android.os;
+import android.util.Slog;
+
import com.google.android.collect.Maps;
import java.util.HashMap;
@@ -81,7 +83,7 @@
if (state != null) {
return state;
} else {
- throw new IllegalStateException("Service " + service + " in unknown state " + rawState);
+ return State.STOPPED;
}
}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 0843d85..d33bd80 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -28,6 +28,9 @@
/** @hide A user id to indicate all users on the device */
public static final int USER_ALL = -1;
+ /** @hide A user handle to indicate all users on the device */
+ public static final UserHandle ALL = new UserHandle(USER_ALL);
+
/** @hide A user id to indicate the currently active user */
public static final int USER_CURRENT = -2;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0338ee7..de8e78c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -56,6 +56,7 @@
/**
* Returns the user name of the user making this call.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @return the user name
*/
public String getUserName() {
@@ -69,6 +70,7 @@
/**
* Returns the UserInfo object describing a specific user.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle the user handle of the user whose information is being requested.
* @return the UserInfo object for a specific user.
* @hide
@@ -84,6 +86,7 @@
/**
* Creates a user with the specified name and options.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @param name the user's name
* @param flags flags that identify the type of user and other properties.
@@ -103,6 +106,7 @@
/**
* Returns information for all users on this device.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @return the list of users that were created.
* @hide
*/
@@ -117,6 +121,7 @@
/**
* Removes a user and all associated data.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle the integer handle of the user, where 0 is the primary user.
* @hide
*/
@@ -131,6 +136,7 @@
/**
* Updates the user's name.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @param userHandle the user's integer handle
* @param name the new name for the user
@@ -162,6 +168,7 @@
/**
* Enable or disable the use of a guest account. If disabled, the existing guest account
* will be wiped.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param enable whether to enable a guest account.
* @hide
*/
@@ -175,6 +182,7 @@
/**
* Checks if a guest user is enabled for this device.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @return whether a guest user is enabled
* @hide
*/
@@ -189,6 +197,7 @@
/**
* Wipes all the data for a user, but doesn't remove the user.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle
* @hide
*/
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
old mode 100644
new mode 100755
index 0c16565..08621ea
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8362,7 +8362,7 @@
// Line contains the query string - now search for it at the start of tokens.
List<String> lineTokens = new ArrayList<String>();
List<Integer> tokenOffsets = new ArrayList<Integer>();
- split(contentLine.trim(), lineTokens, tokenOffsets);
+ split(contentLine, lineTokens, tokenOffsets);
// As we find matches against the query, we'll populate this list with the marked
// (or unchanged) tokens.
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 79d0144..48d84c1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -120,7 +120,7 @@
*/
public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
"android.media.action.MEDIA_PLAY_FROM_SEARCH";
-
+
/**
* The name of the Intent-extra used to define the artist
*/
@@ -173,6 +173,23 @@
public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
/**
+ * The name of the Intent action used to launch a camera in still image mode
+ * for use when the device is secured (e.g. with a pin, password, pattern,
+ * or face unlock). Applications responding to this intent must not expose
+ * any personal content like existing photos or videos on the device. The
+ * applications should be careful not to share any photo or video with other
+ * applications or internet. The activity should use {@link
+ * android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} to display
+ * on top of the lock screen while secured. There is no activity stack when
+ * this flag is used, so launching more than one activity is strongly
+ * discouraged.
+ *
+ * @hide
+ */
+ public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
+ "android.media.action.STILL_IMAGE_CAMERA_SECURE";
+
+ /**
* The name of the Intent action used to launch a camera in video mode.
*/
public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 28273f0..1f6f0dd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4248,27 +4248,40 @@
"setup_prepaid_detection_redir_host";
/**
- * Whether the screensaver is enabled.
+ * Whether screensavers are enabled.
* @hide
*/
public static final String SCREENSAVER_ENABLED = "screensaver_enabled";
/**
- * The user's chosen screensaver component.
+ * The user's chosen screensaver components.
*
- * This component will be launched by the PhoneWindowManager after a timeout when not on
+ * These will be launched by the PhoneWindowManager after a timeout when not on
* battery, or upon dock insertion (if SCREENSAVER_ACTIVATE_ON_DOCK is set to 1).
* @hide
*/
- public static final String SCREENSAVER_COMPONENT = "screensaver_component";
+ public static final String SCREENSAVER_COMPONENTS = "screensaver_components";
/**
- * Whether the screensaver should be automatically launched when the device is inserted
- * into a (desk) dock.
+ * If screensavers are enabled, whether the screensaver should be automatically launched
+ * when the device is inserted into a (desk) dock.
* @hide
*/
public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock";
+ /**
+ * If screensavers are enabled, whether the screensaver should be automatically launched
+ * when the screen times out when not on battery.
+ * @hide
+ */
+ public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep";
+
+ /**
+ * If screensavers are enabled, the default screensaver component.
+ * @hide
+ */
+ public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
+
/** {@hide} */
public static final String NETSTATS_ENABLED = "netstats_enabled";
/** {@hide} */
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index 69db97c..ba2ac67 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -56,6 +56,10 @@
public static final String SERVICE_INTERFACE =
"android.service.dreams.Dream";
+ /** Service meta-data key for declaring an optional configuration activity. */
+ public static final String METADATA_NAME_CONFIG_ACTIVITY =
+ "android.service.dreams.config_activity";
+
private Window mWindow;
private WindowManager mWindowManager;
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index 5d6b17e..2cec6c3 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -1,7 +1,7 @@
package android.service.dreams;
-import static android.provider.Settings.Secure.SCREENSAVER_COMPONENT;
-
+import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
+import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,7 +58,8 @@
// IDreamManager method
@Override
public void dream() {
- ComponentName name = getDreamComponent();
+ ComponentName[] dreams = getDreamComponents();
+ ComponentName name = dreams != null && dreams.length > 0 ? dreams[0] : null;
if (name != null) {
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
@@ -73,21 +74,45 @@
// IDreamManager method
@Override
- public void setDreamComponent(ComponentName name) {
- Settings.Secure.putString(mContext.getContentResolver(), SCREENSAVER_COMPONENT, name.flattenToString());
+ public void setDreamComponents(ComponentName[] componentNames) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ SCREENSAVER_COMPONENTS,
+ componentsToString(componentNames));
+ }
+
+ private static String componentsToString(ComponentName[] componentNames) {
+ StringBuilder names = new StringBuilder();
+ if (componentNames != null) {
+ for (ComponentName componentName : componentNames) {
+ if (names.length() > 0)
+ names.append(',');
+ names.append(componentName.flattenToString());
+ }
+ }
+ return names.toString();
+ }
+
+ private static ComponentName[] componentsFromString(String names) {
+ String[] namesArray = names.split(",");
+ ComponentName[] componentNames = new ComponentName[namesArray.length];
+ for (int i = 0; i < namesArray.length; i++)
+ componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+ return componentNames;
}
// IDreamManager method
@Override
- public ComponentName getDreamComponent() {
+ public ComponentName[] getDreamComponents() {
// TODO(dsandler) don't load this every time, watch the value
- String component = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENT);
- if (component != null) {
- return ComponentName.unflattenFromString(component);
- } else {
- // We rely on DatabaseHelper to set a sane default for us when the settings DB is upgraded
- return null;
- }
+ String names = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENTS);
+ return names == null ? null : componentsFromString(names);
+ }
+
+ // IDreamManager method
+ @Override
+ public ComponentName getDefaultDreamComponent() {
+ String name = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_DEFAULT_COMPONENT);
+ return name == null ? null : ComponentName.unflattenFromString(name);
}
// IDreamManager method
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index b64dd8f..b6fcdf0 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -24,8 +24,9 @@
interface IDreamManager {
void dream();
void awaken();
- void setDreamComponent(in ComponentName componentName);
- ComponentName getDreamComponent();
+ void setDreamComponents(in ComponentName[] componentNames);
+ ComponentName[] getDreamComponents();
+ ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
}
\ No newline at end of file
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ac3dee4..9051285 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -357,11 +357,6 @@
// From the Unicode Line Breaking Algorithm (at least approximately)
boolean isLineBreak = isSpaceOrTab ||
- // .,:; are class IS breakpoints, except when adjacent to digits
- ((c == CHAR_DOT || c == CHAR_COMMA ||
- c == CHAR_COLON || c == CHAR_SEMICOLON) &&
- (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) &&
- (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
// / is class SY and - is class HY, except when followed by a digit
((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
(j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
@@ -959,10 +954,6 @@
private static final char CHAR_NEW_LINE = '\n';
private static final char CHAR_TAB = '\t';
private static final char CHAR_SPACE = ' ';
- private static final char CHAR_DOT = '.';
- private static final char CHAR_COMMA = ',';
- private static final char CHAR_COLON = ':';
- private static final char CHAR_SEMICOLON = ';';
private static final char CHAR_SLASH = '/';
private static final char CHAR_HYPHEN = '-';
diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java
index e05169a..9556223 100644
--- a/core/java/android/util/FloatMath.java
+++ b/core/java/android/util/FloatMath.java
@@ -82,6 +82,16 @@
public static native float exp(float value);
/**
+ * Returns the closest float approximation of the result of raising {@code
+ * x} to the power of {@code y}.
+ *
+ * @param x the base of the operation.
+ * @param y the exponent of the operation.
+ * @return {@code x} to the power of {@code y}.
+ */
+ public static native float pow(float x, float y);
+
+ /**
* Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
* {@code y}</i><sup>{@code 2}</sup>{@code )}.
*
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 517b514..a6d1a3f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -388,8 +388,8 @@
/** Free all server-side state associated with this surface and
* release this object's reference. @hide */
public native void destroy();
-
- private native Canvas lockCanvasNative(Rect dirty);
+
+ private native Canvas lockCanvasNative(Rect dirty) throws OutOfResourcesException;
/**
* set the orientation of the given display.
@@ -497,10 +497,10 @@
}
private native void init(SurfaceSession s,
- int pid, String name, int displayId, int w, int h, int format, int flags)
+ int pid, String name, int layerStack, int w, int h, int format, int flags)
throws OutOfResourcesException;
- private native void init(Parcel source);
+ private native void init(Parcel source) throws OutOfResourcesException;
private native void initFromSurfaceTexture(SurfaceTexture surfaceTexture);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 548d4ad9..e754adc 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1577,8 +1577,8 @@
try {
if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod);
final long startTime = SystemClock.uptimeMillis();
- mCurMethod.dispatchKeyEvent(seq, key, mInputMethodCallback);
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
+ mCurMethod.dispatchKeyEvent(seq, key, mInputMethodCallback);
return;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e);
@@ -1602,8 +1602,8 @@
try {
if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod);
final long startTime = SystemClock.uptimeMillis();
- mCurMethod.dispatchTrackballEvent(seq, motion, mInputMethodCallback);
enqueuePendingEventLocked(startTime, seq, mCurId, callback);
+ mCurMethod.dispatchTrackballEvent(seq, motion, mInputMethodCallback);
return;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e);
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index b3571aa..296d960 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -28,9 +28,9 @@
public class HttpAuthHandler extends Handler {
/**
- * Package-private constructor needed for API compatibility.
+ * @hide Only for use by WebViewProvider implementations.
*/
- HttpAuthHandler() {
+ public HttpAuthHandler() {
}
/**
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 426145a..3a43950 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -26,9 +26,9 @@
public class SslErrorHandler extends Handler {
/**
- * Package-private constructor needed for API compatibility.
+ * @hide Only for use by WebViewProvider implementations.
*/
- SslErrorHandler() {}
+ public SslErrorHandler() {}
/**
* Proceed with the SSL certificate.
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 074f910..e8ff01f 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -17,8 +17,6 @@
package android.webkit;
import android.content.Context;
-import android.os.Message;
-import android.os.Build;
/**
* Manages settings state for a WebView. When a WebView is first created, it
@@ -423,7 +421,7 @@
* Gets the text zoom of the page in percent.
*
* @return the text zoom of the page in percent
- * @see #setTextSizeZoom
+ * @see #setTextZoom
*/
public synchronized int getTextZoom() {
throw new MustOverrideException();
@@ -436,7 +434,7 @@
* @deprecated Use {@link #setTextZoom} instead.
*/
public synchronized void setTextSize(TextSize t) {
- throw new MustOverrideException();
+ setTextZoom(t.value);
}
/**
@@ -449,7 +447,20 @@
* @deprecated Use {@link #getTextZoom} instead.
*/
public synchronized TextSize getTextSize() {
- throw new MustOverrideException();
+ TextSize closestSize = null;
+ int smallestDelta = Integer.MAX_VALUE;
+ int textSize = getTextZoom();
+ for (TextSize size : TextSize.values()) {
+ int delta = Math.abs(textSize - size.value);
+ if (delta == 0) {
+ return size;
+ }
+ if (delta < smallestDelta) {
+ smallestDelta = delta;
+ closestSize = size;
+ }
+ }
+ return closestSize != null ? closestSize : TextSize.NORMAL;
}
/**
@@ -1235,7 +1246,7 @@
* @param context a Context object used to access application assets
*/
public static String getDefaultUserAgent(Context context) {
- return WebView.getFactory().getDefaultUserAgent(context);
+ return WebViewFactory.getProvider().getStatics().getDefaultUserAgent(context);
}
/**
diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java
index eac1141..d1f8b4b 100644
--- a/core/java/android/webkit/WebSettingsClassic.java
+++ b/core/java/android/webkit/WebSettingsClassic.java
@@ -665,34 +665,6 @@
}
/**
- * @see android.webkit.WebSettings#setTextSize(android.webkit.WebSettingsClassic.TextSize)
- */
- @Override
- public synchronized void setTextSize(TextSize t) {
- setTextZoom(t.value);
- }
-
- /**
- * @see android.webkit.WebSettings#getTextSize()
- */
- @Override
- public synchronized TextSize getTextSize() {
- TextSize closestSize = null;
- int smallestDelta = Integer.MAX_VALUE;
- for (TextSize size : TextSize.values()) {
- int delta = Math.abs(mTextSize - size.value);
- if (delta == 0) {
- return size;
- }
- if (delta < smallestDelta) {
- smallestDelta = delta;
- closestSize = size;
- }
- }
- return closestSize != null ? closestSize : TextSize.NORMAL;
- }
-
- /**
* Set the double-tap zoom of the page in percent. Default is 100.
* @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4c5699b..82635d7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -310,15 +310,15 @@
/**
* Notifies the listener about progress made by a find operation.
*
- * @param numberOfMatches how many matches have been found
* @param activeMatchOrdinal the zero-based ordinal of the currently selected match
+ * @param numberOfMatches how many matches have been found
* @param isDoneCounting whether the find operation has actually completed. The listener
* may be notified multiple times while the
* operation is underway, and the numberOfMatches
* value should not be considered final unless
* isDoneCounting is true.
*/
- public void onFindResultReceived(int numberOfMatches, int activeMatchOrdinal,
+ public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
boolean isDoneCounting);
}
@@ -1821,7 +1821,7 @@
}
}
- static synchronized WebViewFactoryProvider getFactory() {
+ private static synchronized WebViewFactoryProvider getFactory() {
// For now the main purpose of this function (and the factory abstration) is to keep
// us honest and minimize usage of WebViewClassic internals when binding the proxy.
checkThread();
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index b1d42aa..934ef83 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -42,6 +42,12 @@
* {@link android.webkit.WebView#disablePlatformNotifications()}
*/
void setPlatformNotificationsEnabled(boolean enable);
+
+ /**
+ * Implements the API method:
+ * {@link android.webkit.WebSettings#getDefaultUserAgent(Context) }
+ */
+ String getDefaultUserAgent(Context context);
}
Statics getStatics();
@@ -93,14 +99,4 @@
* @return the singleton WebViewDatabase instance
*/
WebViewDatabase getWebViewDatabase(Context context);
-
- /**
- * Returns the default User-Agent used by a WebView.
- * An instance of WebView could use a different User-Agent if a call
- * is made to {@link WebSettings#setUserAgent(int)} or
- * {@link WebSettings#setUserAgentString(String)}.
- *
- * @param context a Context object used to access application assets
- */
- String getDefaultUserAgent(Context context);
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 61c942d..423135f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -973,6 +973,12 @@
// Start selection mode if needed. We don't need to if we're unchecking something.
if (value && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+ if (mMultiChoiceModeCallback == null ||
+ !mMultiChoiceModeCallback.hasWrappedCallback()) {
+ throw new IllegalStateException("AbsListView: attempted to start selection mode " +
+ "for CHOICE_MODE_MULTIPLE_MODAL but no choice mode callback was " +
+ "supplied. Call setMultiChoiceModeListener to set a callback.");
+ }
mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
}
@@ -5945,6 +5951,10 @@
mWrapped = wrapped;
}
+ public boolean hasWrappedCallback() {
+ return mWrapped != null;
+ }
+
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
if (mWrapped.onCreateActionMode(mode, menu)) {
// Initialize checked graphic state?
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index f91201a..bc78adc 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -175,11 +175,7 @@
@Override
protected void internalSetPadding(int left, int top, int right, int bottom) {
super.internalSetPadding(left, top, right, bottom);
- if (isLayoutRtl()) {
- mBasePadding = mUserPaddingLeft;
- } else {
- mBasePadding = mUserPaddingRight;
- }
+ setBasePadding(isLayoutRtl());
}
@Override
@@ -201,13 +197,21 @@
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
- mBasePadding = getPaddingEnd();
+ setBasePadding(isLayoutRtl());
}
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
- mBasePadding = getPaddingEnd();
+ setBasePadding(isLayoutRtl());
+ }
+
+ private void setBasePadding(boolean isLayoutRtl) {
+ if (isLayoutRtl) {
+ mBasePadding = mPaddingLeft;
+ } else {
+ mBasePadding = mPaddingRight;
+ }
}
@Override
@@ -237,11 +241,11 @@
final int left;
final int right;
if (isLayoutRtl) {
- right = getPaddingEnd();
- left = right - mCheckMarkWidth;
- } else {
- left = width - getPaddingEnd();
+ left = mBasePadding;
right = left + mCheckMarkWidth;
+ } else {
+ right = width - mBasePadding;
+ left = right - mCheckMarkWidth;
}
checkMarkDrawable.setBounds( left, top, right, bottom);
checkMarkDrawable.draw(canvas);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 18c4fe6..ff0579c 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -22,6 +22,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.FocusFinder;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -62,6 +63,7 @@
private static final float MAX_SCROLL_FACTOR = ScrollView.MAX_SCROLL_FACTOR;
+ private static final String TAG = "HorizontalScrollView";
private long mLastScroll;
@@ -456,6 +458,12 @@
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
+ if (pointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + activePointerId
+ + " in onInterceptTouchEvent");
+ break;
+ }
+
final int x = (int) ev.getX(pointerIndex);
final int xDiff = (int) Math.abs(x - mLastMotionX);
if (xDiff > mTouchSlop) {
@@ -557,6 +565,11 @@
}
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (activePointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
+ break;
+ }
+
final int x = (int) ev.getX(activePointerIndex);
int deltaX = mLastMotionX - x;
if (!mIsBeingDragged && Math.abs(deltaX) > mTouchSlop) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 1711154..bc41931 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.os.StrictMode;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.FocusFinder;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -69,6 +70,8 @@
static final float MAX_SCROLL_FACTOR = 0.5f;
+ private static final String TAG = "ScrollView";
+
private long mLastScroll;
private final Rect mTempRect = new Rect();
@@ -485,6 +488,12 @@
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
+ if (pointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + activePointerId
+ + " in onInterceptTouchEvent");
+ break;
+ }
+
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop) {
@@ -592,6 +601,11 @@
}
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (activePointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
+ break;
+ }
+
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index b8ffe8d..113299a 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -184,6 +184,10 @@
mShrinkableColumns = new SparseBooleanArray();
}
+ // TableLayouts are always in vertical orientation; keep this tracked
+ // for shared LinearLayout code.
+ setOrientation(VERTICAL);
+
mPassThroughListener = new PassThroughHierarchyChangeListener();
// make sure to call the parent class method to avoid potential
// infinite loops
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index ff1dd11..7c8196d 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -284,6 +284,7 @@
mVideoHeight = mp.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
+ requestLayout();
}
}
};
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 52cb679..7d1231e 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -28,9 +28,12 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
+import android.widget.TextView;
import java.text.Collator;
import java.util.Arrays;
@@ -86,7 +89,7 @@
}
public static ArrayAdapter<LocaleInfo> constructAdapter(Context context,
- int layoutId, int fieldId) {
+ final int layoutId, final int fieldId) {
final Resources resources = context.getResources();
final String[] locales = Resources.getSystem().getAssets().getLocales();
final String[] specialLocaleCodes = resources.getStringArray(R.array.special_locale_codes);
@@ -154,7 +157,29 @@
localeInfos[i] = preprocess[i];
}
Arrays.sort(localeInfos);
- return new ArrayAdapter<LocaleInfo>(context, layoutId, fieldId, localeInfos);
+
+ final LayoutInflater inflater =
+ (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ return new ArrayAdapter<LocaleInfo>(context, layoutId, fieldId, localeInfos) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view;
+ TextView text;
+ if (convertView == null) {
+ view = inflater.inflate(layoutId, parent, false);
+ text = (TextView) view.findViewById(fieldId);
+ view.setTag(text);
+ } else {
+ view = convertView;
+ text = (TextView) view.getTag();
+ }
+ LocaleInfo item = getItem(position);
+ text.setText(item.toString());
+ text.setTextLocale(item.getLocale());
+
+ return view;
+ }
+ };
}
private static String toTitleCase(String s) {
@@ -230,4 +255,4 @@
// Intentionally left blank
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 246b0c9..c5e7d9d 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -49,6 +49,7 @@
public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
public static final int RECOMMEND_FAILED_INVALID_URI = -6;
+ public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
private static final boolean localLOGV = true;
private static final String TAG = "PackageHelper";
diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java
index b620abac..d6f6d0b 100644
--- a/core/java/com/android/internal/net/LegacyVpnInfo.java
+++ b/core/java/com/android/internal/net/LegacyVpnInfo.java
@@ -17,8 +17,10 @@
package com.android.internal.net;
import android.app.PendingIntent;
+import android.net.NetworkInfo;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
/**
* A simple container used to carry information of the ongoing legacy VPN.
@@ -27,6 +29,8 @@
* @hide
*/
public class LegacyVpnInfo implements Parcelable {
+ private static final String TAG = "LegacyVpnInfo";
+
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_INITIALIZING = 1;
public static final int STATE_CONNECTING = 2;
@@ -66,4 +70,25 @@
return new LegacyVpnInfo[size];
}
};
+
+ /**
+ * Return best matching {@link LegacyVpnInfo} state based on given
+ * {@link NetworkInfo}.
+ */
+ public static int stateFromNetworkInfo(NetworkInfo info) {
+ switch (info.getDetailedState()) {
+ case CONNECTING:
+ return STATE_CONNECTING;
+ case CONNECTED:
+ return STATE_CONNECTED;
+ case DISCONNECTED:
+ return STATE_DISCONNECTED;
+ case FAILED:
+ return STATE_FAILED;
+ default:
+ Log.w(TAG, "Unhandled state " + info.getDetailedState()
+ + " ; treating as disconnected");
+ return STATE_DISCONNECTED;
+ }
+ }
}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index d6f9e07..956653b 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
import java.util.List;
/**
@@ -45,13 +47,14 @@
}
public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) {
+ Preconditions.checkNotNull(config);
+
Intent intent = new Intent();
intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
intent.putExtra("config", config);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- return PendingIntent.getActivity(context, 0, intent, (config == null) ?
- PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT);
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
public String user;
@@ -64,6 +67,7 @@
public List<String> searchDomains;
public PendingIntent configureIntent;
public long startTime = -1;
+ public boolean legacy;
@Override
public int describeContents() {
@@ -82,6 +86,7 @@
out.writeStringList(searchDomains);
out.writeParcelable(configureIntent, flags);
out.writeLong(startTime);
+ out.writeInt(legacy ? 1 : 0);
}
public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -99,6 +104,7 @@
config.searchDomains = in.createStringArrayList();
config.configureIntent = in.readParcelable(null);
config.startTime = in.readLong();
+ config.legacy = in.readInt() != 0;
return config;
}
diff --git a/core/java/com/android/internal/net/VpnProfile.aidl b/core/java/com/android/internal/net/VpnProfile.aidl
new file mode 100644
index 0000000..a072160
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnProfile.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 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 com.android.internal.net;
+
+parcelable VpnProfile;
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 154b16b..d6c5702 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -16,6 +16,9 @@
package com.android.internal.net;
+import android.os.Parcel;
+import android.os.Parcelable;
+
import java.nio.charset.Charsets;
/**
@@ -27,7 +30,7 @@
*
* @hide
*/
-public class VpnProfile implements Cloneable {
+public class VpnProfile implements Cloneable, Parcelable {
// Match these constants with R.array.vpn_types.
public static final int TYPE_PPTP = 0;
public static final int TYPE_L2TP_IPSEC_PSK = 1;
@@ -120,4 +123,28 @@
builder.append('\0').append(ipsecServerCert);
return builder.toString().getBytes(Charsets.UTF_8);
}
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(key);
+ out.writeByteArray(encode());
+ }
+
+ public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
+ @Override
+ public VpnProfile createFromParcel(Parcel in) {
+ final String key = in.readString();
+ return decode(key, in.createByteArray());
+ }
+
+ @Override
+ public VpnProfile[] newArray(int size) {
+ return new VpnProfile[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 1e268c4..d6f1807 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -527,8 +527,6 @@
"Duplicate arg specified");
}
niceName = arg.substring(arg.indexOf('=') + 1);
- } else if (arg.equals("--mount-external-singleuser")) {
- mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
} else if (arg.equals("--mount-external-multiuser")) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
} else {
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index a53a9c0..a327adc 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -54,4 +54,16 @@
return reference;
}
+ /**
+ * Ensures the truth of an expression involving the state of the calling
+ * instance, but not involving any parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @throws IllegalStateException if {@code expression} is false
+ */
+ public static void checkState(boolean expression) {
+ if (!expression) {
+ throw new IllegalStateException();
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 08d9f49..b620568 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -23,7 +23,9 @@
import android.app.ActionBar;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
import android.view.View;
@@ -38,6 +40,7 @@
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
/**
* This widget implements the dynamic action bar tab behavior that can change
@@ -352,7 +355,7 @@
tabView.getTab().select();
}
- private class TabView extends LinearLayout {
+ private class TabView extends LinearLayout implements OnLongClickListener {
private ActionBar.Tab mTab;
private TextView mTextView;
private ImageView mIconView;
@@ -426,7 +429,8 @@
mIconView.setImageDrawable(null);
}
- if (text != null) {
+ final boolean hasText = !TextUtils.isEmpty(text);
+ if (hasText) {
if (mTextView == null) {
TextView textView = new TextView(getContext(), null,
com.android.internal.R.attr.actionBarTabTextStyle);
@@ -448,9 +452,35 @@
if (mIconView != null) {
mIconView.setContentDescription(tab.getContentDescription());
}
+
+ if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+ setOnLongClickListener(this);
+ } else {
+ setOnLongClickListener(null);
+ setLongClickable(false);
+ }
}
}
+ public boolean onLongClick(View v) {
+ final int[] screenPos = new int[2];
+ getLocationOnScreen(screenPos);
+
+ final Context context = getContext();
+ final int width = getWidth();
+ final int height = getHeight();
+ final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
+
+ Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
+ Toast.LENGTH_SHORT);
+ // Show under the tab
+ cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
+ (screenPos[0] + width / 2) - screenWidth / 2, height);
+
+ cheatSheet.show();
+ return true;
+ }
+
public ActionBar.Tab getTab() {
return mTab;
}
diff --git a/core/jni/android_util_FloatMath.cpp b/core/jni/android_util_FloatMath.cpp
index 529fbe9..73b7a6f 100644
--- a/core/jni/android_util_FloatMath.cpp
+++ b/core/jni/android_util_FloatMath.cpp
@@ -30,6 +30,10 @@
return expf(x);
}
+ static float PowF(JNIEnv* env, jobject clazz, float x, float y) {
+ return powf(x, y);
+ }
+
static float HypotF(JNIEnv* env, jobject clazz, float x, float y) {
return hypotf(x, y);
}
@@ -42,6 +46,7 @@
{"cos", "(F)F", (void*) MathUtilsGlue::CosF},
{"sqrt", "(F)F", (void*) MathUtilsGlue::SqrtF},
{"exp", "(F)F", (void*) MathUtilsGlue::ExpF},
+ {"pow", "(FF)F", (void*) MathUtilsGlue::PowF},
{"hypot", "(FF)F", (void*) MathUtilsGlue::HypotF},
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 89be5cb..1c9b440 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -790,7 +790,7 @@
third party applications. -->
<permission android:name="android.permission.MANAGE_USERS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signature"
+ android:protectionLevel="signature|system"
android:label="@string/permlab_manageUsers"
android:description="@string/permdesc_manageUsers" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ad03dd2..560a6a8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -224,10 +224,8 @@
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Laat die program toe om aksies vir verskillende gebruikers op die toestel uit te voer. Kwaadwillige programme kan dit gebruik om die beskerming tussen gebruikers te skend."</string>
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volle lisensie vir interaksie tussen gebruikers"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Laat alle moontlike interaksies tussen gebruikers toe."</string>
- <!-- no translation found for permlab_manageUsers (1676150911672282428) -->
- <skip />
- <!-- no translation found for permdesc_manageUsers (8409306667645355638) -->
- <skip />
+ <string name="permlab_manageUsers" msgid="1676150911672282428">"bestuur gebruikers"</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"Laat programme toe om gebruikers op die toestel te bestuur, insluitend navrae, skepping en uitvee."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"haal besonderhede van lopende programme op"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Laat die program toe om inligting op te haal oor huidige en onlangse lopende take. Kwaadwillige programme kan dalk private inligting oor ander programme ontdek."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"herrangskik lopende programme"</string>
@@ -1313,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ingeboude skerm"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 14d95a5..d3b8f04 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"تم"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"شاشة مدمجة"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 81ba8a7..7e7c4e6 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Вграден екран"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4e7da84..50cd013 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Integrovaná obrazovka"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 9108337..00d8617 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Pantalla integrada"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c998ff6..5e63311 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -225,7 +225,7 @@
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licencia completa para interactuar con los usuarios"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite que la aplicación interactúe con los usuarios."</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"administrar usuarios"</string>
- <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite a las aplicaciones administrar los usuarios del dispositivo, así como buscarlos, crearlos y eliminarlos."</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite a las aplicaciones administrar los usuarios del dispositivo, p. ej., buscarlos, crearlos y eliminarlos."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recuperar información de aplicaciones en ejecución"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Las aplicaciones malintencionadas pueden usar este servicio para acceder a información privada sobre otras aplicaciones."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"reorganizar aplicaciones en ejecución"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 872f485..8280b61 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Sisseehitatud ekraan"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ecdebe8..0dba1bd 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوثهای صوتی"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"صفحه نمایش از خود"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c35fe8d..d4d938b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Écran intégré"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6ea8f7b..b491e97 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"अंतर्निहित स्क्रीन"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 26bc6ec..aef3bdf 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ugrađeni zaslon"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 42e7888..90bd85e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Beépített képernyő"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index dc0c139..b7a9c3b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"内蔵画面"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f6ae2af..0193ca2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"기본으로 제공되는 화면"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 7692620..b778d03 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -225,7 +225,7 @@
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"visa licencija, leidžianti sąveikauti su naudotojais"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Leidžiama bet kokia sąveika tarp naudotojų."</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"tvarkyti naudotojus"</string>
- <string name="permdesc_manageUsers" msgid="8409306667645355638">"Leidžia tvarkyti įrenginio naudotojų duomenis, įskaitant užklausų teikimą, duomenų kūrimą ir ištrynimą."</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"Leidžia programoms tvarkyti įrenginio naudotojų duomenis, įskaitant užklausų teikimą, duomenų kūrimą ir ištrynimą."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"nuskaityti veikiančių programų išsamią informaciją"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Leidžiama programai nuskaityti išsamią informaciją apie šiuo ir pastaruoju metu vykdomas užduotis. Kenkėjiškos programos gali surasti privačios informacijos apie kitas programas."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"pertvarkyti vykdomas programas"</string>
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Atlikta"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Integruotas ekranas"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d63c45b..4b78bd4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gatavs"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Iebūvēts ekrāns"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a22ff51..782c2a7 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Skrin Terbina Dalam"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e16d308..f0dcc2f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotowe"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Wbudowany ekran"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 996be49..18c25a3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ecrã Integrado"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 7d7672f..794af68 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Tela integrada"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6300a1f4..6f6272d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ecran încorporat"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 004b2b6..a9c0701 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Встроенный экран"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 15c359c..6240be3 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Vstavaná obrazovka"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e4cf347..4ddde21 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Уграђени екран"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c25e6db..efb1d6f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"หน้าจอในตัว"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index ab4ff29..261a0b9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Built-in na Screen"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 95637dc..c60535f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Yerleşik Ekran"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 384a1ee..012a47a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Màn hình tích hợp"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 289dcf8..e982c75 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"内置屏幕"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 96ba8c1..36eba9f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"內建畫面"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2a17f8f..78b287c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1311,6 +1311,5 @@
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
<string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Qedile"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
- <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
- <skip />
+ <string name="display_manager_built_in_display" msgid="9042666544146043569">"Okwakhelwe ngaphakathi kwesikrini"</string>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e3c957b..86d03ad 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -554,9 +554,22 @@
<integer-array name="config_autoBrightnessLevels">
</integer-array>
+ <!-- Minimum screen brightness setting allowed by the power manager.
+ The user is forbidden from setting the brightness below this level. -->
+ <integer name="config_screenBrightnessSettingMinimum">10</integer>
- <!-- Minimum screen brightness allowed by the power manager. -->
- <integer name="config_screenBrightnessDim">20</integer>
+ <!-- Maximum screen brightness allowed by the power manager.
+ The user is forbidden from setting the brightness above this level. -->
+ <integer name="config_screenBrightnessSettingMaximum">255</integer>
+
+ <!-- Default screen brightness setting.
+ Must be in the range specified by minimum and maximum. -->
+ <integer name="config_screenBrightnessSettingDefault">102</integer>
+
+ <!-- Screen brightness used to dim the screen when the user activity
+ timeout expires. May be less than the minimum allowed brightness setting
+ that can be set by the user. -->
+ <integer name="config_screenBrightnessDim">10</integer>
<!-- Array of output values for LCD backlight corresponding to the LUX values
in the config_autoBrightnessLevels array. This array should have size one greater
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0d190ee..e17a05d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1471,6 +1471,9 @@
<java-symbol type="integer" name="config_notificationsBatteryLowARGB" />
<java-symbol type="integer" name="config_notificationsBatteryMediumARGB" />
<java-symbol type="integer" name="config_radioScanningTimeout" />
+ <java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
+ <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
+ <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 6e1b9d6..a1fd14e 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -864,7 +864,7 @@
public void deleteFromRawResource(int iFlags, int dFlags) {
InstallParams ip = sampleInstallFromRawResource(iFlags, false);
- boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0);
+ boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
DeleteObserver observer = new DeleteObserver();
try {
@@ -914,12 +914,12 @@
@LargeTest
public void testDeleteNormalInternalRetainData() {
- deleteFromRawResource(0, PackageManager.DONT_DELETE_DATA);
+ deleteFromRawResource(0, PackageManager.DELETE_KEEP_DATA);
}
@LargeTest
public void testDeleteFwdLockedInternalRetainData() {
- deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DONT_DELETE_DATA);
+ deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DELETE_KEEP_DATA);
}
@LargeTest
@@ -929,7 +929,7 @@
return;
}
- deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DONT_DELETE_DATA);
+ deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA);
}
/* sdcard mount/unmount tests ******/
@@ -1656,7 +1656,7 @@
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
// Delete the package now retaining data.
GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DONT_DELETE_DATA, receiver);
+ invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
assertTrue(invokeMovePackageFail(ip.pkg.packageName, moveFlags, result));
} catch (Exception e) {
failStr(e);
@@ -2532,7 +2532,7 @@
GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
try {
- invokeDeletePackage(ip.pkg.packageName, PackageManager.DONT_DELETE_DATA, receiver);
+ invokeDeletePackage(ip.pkg.packageName, PackageManager.DELETE_KEEP_DATA, receiver);
} catch (Exception e) {
failStr(e);
}
diff --git a/docs/downloads/design/Android_Design_Downloads_20120823.zip b/docs/downloads/design/Android_Design_Downloads_20120823.zip
new file mode 100644
index 0000000..6d31283
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Downloads_20120823.zip
Binary files differ
diff --git a/docs/downloads/design/Roboto_Hinted_20120823.zip b/docs/downloads/design/Roboto_Hinted_20120823.zip
new file mode 100644
index 0000000..9ead4af
--- /dev/null
+++ b/docs/downloads/design/Roboto_Hinted_20120823.zip
Binary files differ
diff --git a/docs/downloads/training/TabCompat.zip b/docs/downloads/training/TabCompat.zip
index b70b442..b907b42 100644
--- a/docs/downloads/training/TabCompat.zip
+++ b/docs/downloads/training/TabCompat.zip
Binary files differ
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index 4503098..5f78aea 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -12,7 +12,7 @@
<div class="layout-content-col span-4">
<p>
- <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Downloads_20120814.zip">Download All</a>
+ <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Downloads_20120823.zip">Download All</a>
</p>
</div>
@@ -91,7 +91,7 @@
<div class="layout-content-col span-4">
<p>
- <a class="download-button" href="{@docRoot}downloads/design/Roboto_Hinted_20111129.zip">Roboto</a>
+ <a class="download-button" href="{@docRoot}downloads/design/Roboto_Hinted_20120823.zip">Roboto</a>
<a class="download-button" href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a>
</p>
diff --git a/docs/html/guide/google/gcm/adv.jd b/docs/html/guide/google/gcm/adv.jd
index 5cb433f..2174128 100644
--- a/docs/html/guide/google/gcm/adv.jd
+++ b/docs/html/guide/google/gcm/adv.jd
@@ -175,7 +175,8 @@
<li>The end user uninstalls the application.</li>
<li>The 3rd-party server sends a message to GCM server.</li>
<li>The GCM server sends the message to the device.</li>
- <li>The GCM client receives the message and queries Package Manager, which returns a "package not found" error.</li>
+ <li>The GCM client receives the message and queries Package Manager about whether there are broadcast receivers configured to receive it, which returns <code>false</code>.
+</li>
<li>The GCM client informs the GCM server that the application was uninstalled.</li>
<li>The GCM server marks the registration ID for deletion.</li>
<li>The 3rd-party server sends a message to GCM.</li>
diff --git a/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html b/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html
index 26916d5..e1bed36 100644
--- a/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html
+++ b/docs/html/guide/google/gcm/client-javadoc/allclasses-frame.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
All Classes
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html b/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html
index 6ae9fe0..dc34021 100644
--- a/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html
+++ b/docs/html/guide/google/gcm/client-javadoc/allclasses-noframe.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
All Classes
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html
index eed1aea..ff15218 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBaseIntentService.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMBaseIntentService
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html
index 2a1c676..ae80bf7 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMBroadcastReceiver.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMBroadcastReceiver
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html
index f778f06..205bcf0 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMConstants.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMConstants
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
@@ -177,8 +177,8 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_APPLICATION_PENDING_INTENT">EXTRA_APPLICATION_PENDING_INTENT</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to get the application
- id.</TD>
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to get the
+ application info.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
@@ -186,16 +186,25 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_ERROR">EXTRA_ERROR</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
an error when the registration fails.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
<CODE>static java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_FROM">EXTRA_FROM</A></B></CODE>
+
+<BR>
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> to indicate which
+ sender (Google API project id) sent the message.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static java.lang.String</CODE></FONT></TD>
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_REGISTRATION_ID">EXTRA_REGISTRATION_ID</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
the registration id when the registration succeeds.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
@@ -204,8 +213,8 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_SENDER">EXTRA_SENDER</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to indicate the sender
- account (a Google email) that owns the application.</TD>
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to indicate which
+ senders (Google API project ids) can send messages to the application.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
@@ -213,7 +222,7 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_SPECIAL_MESSAGE">EXTRA_SPECIAL_MESSAGE</A></B></CODE>
<BR>
- Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE"><CODE>INTENT_FROM_GCM_MESSAGE</CODE></A> intent.</TD>
+ Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> intent.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
@@ -229,7 +238,7 @@
<TD><CODE><B><A HREF="../../../../com/google/android/gcm/GCMConstants.html#EXTRA_UNREGISTERED">EXTRA_UNREGISTERED</A></B></CODE>
<BR>
- Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+ Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
that the application has been unregistered.</TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
@@ -388,8 +397,8 @@
<PRE>
public static final java.lang.String <B>EXTRA_SENDER</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to indicate the sender
- account (a Google email) that owns the application.
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to indicate which
+ senders (Google API project ids) can send messages to the application.
<P>
<DL>
<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_SENDER">Constant Field Values</A></DL>
@@ -401,8 +410,8 @@
<PRE>
public static final java.lang.String <B>EXTRA_APPLICATION_PENDING_INTENT</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>INTENT_TO_GCM_REGISTRATION</CODE></A> to get the application
- id.
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to get the
+ application info.
<P>
<DL>
<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_APPLICATION_PENDING_INTENT">Constant Field Values</A></DL>
@@ -414,7 +423,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_UNREGISTERED</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
that the application has been unregistered.
<P>
<DL>
@@ -427,7 +436,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_ERROR</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
an error when the registration fails. See constants starting with ERROR_
for possible values.
<P>
@@ -441,7 +450,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_REGISTRATION_ID</B></PRE>
<DL>
-<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
the registration id when the registration succeeds.
<P>
<DL>
@@ -454,7 +463,7 @@
<PRE>
public static final java.lang.String <B>EXTRA_SPECIAL_MESSAGE</B></PRE>
<DL>
-<DD>Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE"><CODE>INTENT_FROM_GCM_MESSAGE</CODE></A> intent.
+<DD>Type of message present in the <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> intent.
This extra is only set for special messages sent from GCM, not for
messages originated from the application.
<P>
@@ -482,13 +491,26 @@
<DL>
<DD>Number of messages deleted by the server because the device was idle.
Present only on messages of special type
- <A HREF="../../../../com/google/android/gcm/GCMConstants.html#VALUE_DELETED_MESSAGES"><CODE>VALUE_DELETED_MESSAGES</CODE></A>
+ <A HREF="../../../../com/google/android/gcm/GCMConstants.html#VALUE_DELETED_MESSAGES">"deleted_messages"</A>
<P>
<DL>
<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_TOTAL_DELETED">Constant Field Values</A></DL>
</DL>
<HR>
+<A NAME="EXTRA_FROM"><!-- --></A><H3>
+EXTRA_FROM</H3>
+<PRE>
+public static final java.lang.String <B>EXTRA_FROM</B></PRE>
+<DL>
+<DD>Extra used on <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> to indicate which
+ sender (Google API project id) sent the message.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.google.android.gcm.GCMConstants.EXTRA_FROM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
<A NAME="PERMISSION_GCM_INTENTS"><!-- --></A><H3>
PERMISSION_GCM_INTENTS</H3>
<PRE>
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html
index bb486ff..c29bf90 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/GCMRegistrar.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:36 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
GCMRegistrar
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
@@ -308,11 +308,12 @@
<li>It defines at least one <CODE>BroadcastReceiver</CODE> with category
<code>PACKAGE_NAME</code>.
<li>The <CODE>BroadcastReceiver</CODE>(s) uses the
- permission.
- <li>The <CODE>BroadcastReceiver</CODE>(s) handles the 3 GCM intents
- (,
- ,
- and ).
+ <A HREF="../../../../com/google/android/gcm/GCMConstants.html#PERMISSION_GCM_INTENTS">"com.google.android.c2dm.permission.SEND"</A>
+ permission.
+ <li>The <CODE>BroadcastReceiver</CODE>(s) handles the 2 GCM intents
+ (<A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A>
+ and
+ <A HREF="../../../../com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A>).
</ol>
...where <code>PACKAGE_NAME</code> is the application package.
<p>
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html
index 4828eea..a2a599d 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-frame.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
com.google.android.gcm
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html
index 877248b..c8e0341 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-summary.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
com.google.android.gcm
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html
index bf6fce3..0e27efe 100644
--- a/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html
+++ b/docs/html/guide/google/gcm/client-javadoc/com/google/android/gcm/package-tree.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
com.google.android.gcm Class Hierarchy
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/constant-values.html b/docs/html/guide/google/gcm/client-javadoc/constant-values.html
index 6ccd123..796d196 100644
--- a/docs/html/guide/google/gcm/client-javadoc/constant-values.html
+++ b/docs/html/guide/google/gcm/client-javadoc/constant-values.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Constant Field Values
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
@@ -173,6 +173,12 @@
<TD ALIGN="right"><CODE>"error"</CODE></TD>
</TR>
<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.google.android.gcm.GCMConstants.EXTRA_FROM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public static final java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/google/android/gcm/GCMConstants.html#EXTRA_FROM">EXTRA_FROM</A></CODE></TD>
+<TD ALIGN="right"><CODE>"from"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
<A NAME="com.google.android.gcm.GCMConstants.EXTRA_REGISTRATION_ID"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
<CODE>public static final java.lang.String</CODE></FONT></TD>
<TD ALIGN="left"><CODE><A HREF="com/google/android/gcm/GCMConstants.html#EXTRA_REGISTRATION_ID">EXTRA_REGISTRATION_ID</A></CODE></TD>
diff --git a/docs/html/guide/google/gcm/client-javadoc/default.css b/docs/html/guide/google/gcm/client-javadoc/default.css
index 2513e69..f11daf7 100644
--- a/docs/html/guide/google/gcm/client-javadoc/default.css
+++ b/docs/html/guide/google/gcm/client-javadoc/default.css
@@ -530,12 +530,12 @@
}
.design ol {
counter-reset: item; }
- .design ol li {
+ .design ol>li {
font-size: 14px;
line-height: 20px;
list-style-type: none;
position: relative; }
- .design ol li:before {
+ .design ol>li:before {
content: counter(item) ". ";
counter-increment: item;
position: absolute;
@@ -561,16 +561,18 @@
content: "9. "; }
.design ol li.value-10:before {
content: "10. "; }
-.design .with-callouts ol li {
+.design .with-callouts ol>li {
list-style-position: inside;
margin-left: 0; }
- .design .with-callouts ol li:before {
+ .design .with-callouts ol>li:before {
display: inline;
left: -20px;
float: left;
width: 17px;
color: #33b5e5;
font-weight: 500; }
+.design .with-callouts ul>li {
+ list-style-position: outside; }
/* special list items */
li.no-bullet {
@@ -1079,22 +1081,71 @@
Print Only
========================================================================== */
@media print {
-a {
- color: inherit;
-}
-.nav-x, .nav-y {
- display: none;
-}
-.str { color: #060; }
-.kwd { color: #006; font-weight: bold; }
-.com { color: #600; font-style: italic; }
-.typ { color: #404; font-weight: bold; }
-.lit { color: #044; }
-.pun { color: #440; }
-.pln { color: #000; }
-.tag { color: #006; font-weight: bold; }
-.atn { color: #404; }
-.atv { color: #060; }
+ /* configure printed page */
+ @page {
+ margin: 0.75in 1in;
+ widows: 4;
+ orphans: 4;
+ }
+
+ /* reset spacing metrics */
+ html, body, .wrap {
+ margin: 0 !important;
+ padding: 0 !important;
+ width: auto !important;
+ }
+
+ /* leave enough space on the left for bullets */
+ body {
+ padding-left: 20px !important;
+ }
+ #doc-col {
+ margin-left: 0;
+ }
+
+ /* hide a bunch of non-content elements */
+ #header, #footer, #nav-x, #side-nav,
+ .training-nav-top, .training-nav-bottom,
+ #doc-col .content-footer,
+ .nav-x, .nav-y,
+ .paging-links,
+ a.totop {
+ display: none !important;
+ }
+
+ /* remove extra space above page titles */
+ #doc-col .content-header {
+ margin-top: 0;
+ }
+
+ /* bump up spacing above subheadings */
+ h2 {
+ margin-top: 40px !important;
+ }
+
+ /* print link URLs where possible and give links default text color */
+ p a:after {
+ content: " (" attr(href) ")";
+ font-size: 80%;
+ }
+ p a {
+ word-wrap: break-word;
+ }
+ a {
+ color: inherit;
+ }
+
+ /* syntax highlighting rules */
+ .str { color: #060; }
+ .kwd { color: #006; font-weight: bold; }
+ .com { color: #600; font-style: italic; }
+ .typ { color: #404; font-weight: bold; }
+ .lit { color: #044; }
+ .pun { color: #440; }
+ .pln { color: #000; }
+ .tag { color: #006; font-weight: bold; }
+ .atn { color: #404; }
+ .atv { color: #060; }
}
/* =============================================================================
@@ -2033,8 +2084,11 @@
#jd-content img.toggle-content-img {
margin:0 5px 5px 0;
}
-div.toggle-content > p {
- padding:0 0 5px;
+div.toggle-content p {
+ margin:10px 0 0;
+}
+div.toggle-content-toggleme {
+ padding:0 0 0 15px;
}
@@ -2145,14 +2199,9 @@
.nolist {
list-style:none;
- padding:0;
- margin:0 0 1em 1em;
+ margin-left:0;
}
-.nolist li {
- padding:0 0 2px;
- margin:0;
-}
pre.classic {
background-color:transparent;
@@ -2180,6 +2229,12 @@
color:#666;
}
+div.note,
+div.caution,
+div.warning {
+ margin: 0 0 15px;
+}
+
p.note, div.note,
p.caution, div.caution,
p.warning, div.warning {
@@ -2898,10 +2953,6 @@
/* SEARCH RESULTS */
-/* disable twiddle and size selectors for left column */
-#leftSearchControl div {
- padding:0;
-}
#leftSearchControl .gsc-twiddle {
background-image : none;
@@ -3475,7 +3526,7 @@
.morehover:hover {
opacity:1;
- height:345px;
+ height:385px;
width:268px;
-webkit-transition-property:height, -webkit-opacity;
}
@@ -3489,7 +3540,7 @@
.morehover .mid {
width:228px;
background:url(../images/more_mid.png) repeat-y;
- padding:10px 20px 10px 20px;
+ padding:10px 20px 0 20px;
}
.morehover .mid .header {
@@ -3598,15 +3649,19 @@
padding-top: 14px;
}
+#nav-x .wrap {
+ min-height:34px;
+}
+
#nav-x .wrap,
#searchResults.wrap {
max-width:940px;
border-bottom:1px solid #CCC;
- min-height:34px;
-
}
-
+#searchResults.wrap #leftSearchControl {
+ min-height:700px
+}
.nav-x {
margin-left:0;
margin-bottom:0;
@@ -3762,7 +3817,8 @@
height: 300px;
}
.slideshow-develop img.play {
- width:350px;
+ max-width:350px;
+ max-height:240px;
margin:20px 0 0 90px;
-webkit-transform: perspective(800px ) rotateY( 35deg );
box-shadow: -16px 20px 40px rgba(0, 0, 0, 0.3);
@@ -3817,6 +3873,7 @@
.feed .feed-nav li {
list-style: none;
float: left;
+ height: 21px; /* +4px bottom border = 25px; same as .feed-nav */
margin-right: 25px;
cursor: pointer;
}
@@ -3969,21 +4026,24 @@
.landing-docs {
margin:20px 0 0;
}
-.landing-banner {
- height:280px;
-}
.landing-banner .col-6:first-child,
-.landing-docs .col-6:first-child {
+.landing-docs .col-6:first-child,
+.landing-docs .col-12 {
margin-left:0;
+ min-height:280px;
}
.landing-banner .col-6:last-child,
-.landing-docs .col-6:last-child {
+.landing-docs .col-6:last-child,
+.landing-docs .col-12 {
margin-right:0;
}
.landing-banner h1 {
margin-top:0;
}
+.landing-docs {
+ clear:left;
+}
.landing-docs h3 {
font-size:14px;
line-height:21px;
@@ -4002,4 +4062,99 @@
.plusone {
float:right;
-}
\ No newline at end of file
+}
+
+
+
+/************* HOME/LANDING PAGE *****************/
+
+.slideshow-home {
+ height: 500px;
+ width: 940px;
+ border-bottom: 1px solid #CCC;
+ position: relative;
+ margin: 0;
+}
+.slideshow-home .frame {
+ width: 940px;
+ height: 500px;
+}
+.slideshow-home .content-left {
+ float: left;
+ text-align: center;
+ vertical-align: center;
+ margin: 0 0 0 35px;
+}
+.slideshow-home .content-right {
+ margin: 80px 0 0 0;
+}
+.slideshow-home .content-right p {
+ margin-bottom: 10px;
+}
+.slideshow-home .content-right p:last-child {
+ margin-top: 15px;
+}
+.slideshow-home .content-right h1 {
+ padding:0;
+}
+.slideshow-home .item {
+ height: 500px;
+ width: 940px;
+}
+.home-sections {
+ padding: 30px 20px 20px;
+ margin: 20px 0;
+ background: -webkit-linear-gradient(top, #F6F6F6,#F9F9F9);
+}
+.home-sections ul {
+ margin: 0;
+}
+.home-sections ul li {
+ float: left;
+ display: block;
+ list-style: none;
+ width: 170px;
+ height: 35px;
+ border: 1px solid #ccc;
+ background: white;
+ margin-right: 10px;
+ border-radius: 1px;
+ -webkit-border-radius: 1px;
+ -moz-border-radius: 1px;
+ box-shadow: 1px 1px 5px #EEE;
+ -webkit-box-shadow: 1px 1px 5px #EEE;
+ -moz-box-shadow: 1px 1px 5px #EEE;
+ background: white;
+}
+.home-sections ul li:hover {
+ background: #F9F9F9;
+ border: 1px solid #CCC;
+}
+.home-sections ul li a,
+.home-sections ul li a:hover {
+ font-weight: bold;
+ margin-top: 8px;
+ line-height: 18px;
+ float: left;
+ width: 100%;
+ text-align: center;
+ color: #09c !important;
+}
+.home-sections ul li a {
+ font-weight: bold;
+ margin-top: 8px;
+ line-height: 18px;
+ float: left;
+ width:100%;
+ text-align:center;
+}
+.home-sections ul li img {
+ float: left;
+ margin: -8px 0 0 10px;
+}
+.home-sections ul li.last {
+ margin-right: 0px;
+}
+#footer {
+ margin-top: -40px;
+}
diff --git a/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html b/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html
index 6b86bfe..d9a63c5 100644
--- a/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html
+++ b/docs/html/guide/google/gcm/client-javadoc/deprecated-list.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Deprecated List
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/help-doc.html b/docs/html/guide/google/gcm/client-javadoc/help-doc.html
index ffd1f77..af1bca8 100644
--- a/docs/html/guide/google/gcm/client-javadoc/help-doc.html
+++ b/docs/html/guide/google/gcm/client-javadoc/help-doc.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
API Help
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/client-javadoc/index-all.html b/docs/html/guide/google/gcm/client-javadoc/index-all.html
index 74e6095..408edee 100644
--- a/docs/html/guide/google/gcm/client-javadoc/index-all.html
+++ b/docs/html/guide/google/gcm/client-javadoc/index-all.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Index
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="./default.css" TITLE="Style">
@@ -124,29 +124,33 @@
server that can be retried later.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_APPLICATION_PENDING_INTENT"><B>EXTRA_APPLICATION_PENDING_INTENT</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>GCMConstants.INTENT_TO_GCM_REGISTRATION</CODE></A> to get the application
- id.
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to get the
+ application info.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_ERROR"><B>EXTRA_ERROR</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
an error when the registration fails.
+<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_FROM"><B>EXTRA_FROM</B></A> -
+Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> to indicate which
+ sender (Google API project id) sent the message.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_REGISTRATION_ID"><B>EXTRA_REGISTRATION_ID</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
the registration id when the registration succeeds.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_SENDER"><B>EXTRA_SENDER</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION"><CODE>GCMConstants.INTENT_TO_GCM_REGISTRATION</CODE></A> to indicate the sender
- account (a Google email) that owns the application.
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_TO_GCM_REGISTRATION">"com.google.android.c2dm.intent.REGISTER"</A> to indicate which
+ senders (Google API project ids) can send messages to the application.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_SPECIAL_MESSAGE"><B>EXTRA_SPECIAL_MESSAGE</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Type of message present in the <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE"><CODE>GCMConstants.INTENT_FROM_GCM_MESSAGE</CODE></A> intent.
+<DD>Type of message present in the <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_MESSAGE">"com.google.android.c2dm.intent.RECEIVE"</A> intent.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_TOTAL_DELETED"><B>EXTRA_TOTAL_DELETED</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
<DD>Number of messages deleted by the server because the device was idle.
<DT><A HREF="./com/google/android/gcm/GCMConstants.html#EXTRA_UNREGISTERED"><B>EXTRA_UNREGISTERED</B></A> -
Static variable in class com.google.android.gcm.<A HREF="./com/google/android/gcm/GCMConstants.html" title="class in com.google.android.gcm">GCMConstants</A>
-<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK"><CODE>GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK</CODE></A> to indicate
+<DD>Extra used on <A HREF="./com/google/android/gcm/GCMConstants.html#INTENT_FROM_GCM_REGISTRATION_CALLBACK">"com.google.android.c2dm.intent.REGISTRATION"</A> to indicate
that the application has been unregistered.
</DL>
<HR>
diff --git a/docs/html/guide/google/gcm/client-javadoc/index.html b/docs/html/guide/google/gcm/client-javadoc/index.html
index 26e57f6..fa7af90 100644
--- a/docs/html/guide/google/gcm/client-javadoc/index.html
+++ b/docs/html/guide/google/gcm/client-javadoc/index.html
@@ -2,7 +2,7 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc on Mon Jul 16 14:13:37 PDT 2012-->
+<!-- Generated by javadoc on Wed Aug 22 13:22:47 PDT 2012-->
<TITLE>
Generated Documentation (Untitled)
</TITLE>
diff --git a/docs/html/guide/google/gcm/client-javadoc/overview-tree.html b/docs/html/guide/google/gcm/client-javadoc/overview-tree.html
index c9076f1..392f3e0 100644
--- a/docs/html/guide/google/gcm/client-javadoc/overview-tree.html
+++ b/docs/html/guide/google/gcm/client-javadoc/overview-tree.html
@@ -2,12 +2,12 @@
<!--NewPage-->
<HTML>
<HEAD>
-<!-- Generated by javadoc (build 1.6.0_26) on Mon Jul 16 14:13:37 PDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_26) on Wed Aug 22 13:22:47 PDT 2012 -->
<TITLE>
Class Hierarchy
</TITLE>
-<META NAME="date" CONTENT="2012-07-16">
+<META NAME="date" CONTENT="2012-08-22">
<LINK REL ="stylesheet" TYPE="text/css" HREF="default.css" TITLE="Style">
diff --git a/docs/html/guide/google/gcm/gcm.jd b/docs/html/guide/google/gcm/gcm.jd
index 827edaa..72c3f23 100644
--- a/docs/html/guide/google/gcm/gcm.jd
+++ b/docs/html/guide/google/gcm/gcm.jd
@@ -203,7 +203,7 @@
<p>The registration ID lasts until the Android application explicitly unregisters
itself, or until Google refreshes the registration ID for your Android application.</p>
-<p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled. At that point, you server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).
+<p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents. At that point, you server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).
<p>
Note that it might take a few minutes for the registration ID to be completed removed from the GCM server. So if the 3rd party server sends a message during this time, it will get a valid message ID, even though the message will not be delivered to the device.</p>
</p>
@@ -546,7 +546,7 @@
deliver the messages sent by the 3rd-party server to the application running in the device.
If the server included key-pair values in the <code>data</code> parameter, they are available as
extras in this intent, with the keys being the extra names. GCM also includes an extra called
-<code>from</code> which contains the sender ID as an string.
+<code>from</code> which contains the sender ID as an string, and another called <code>collapse_key</code> containing the collapse key (when in use).
<p>Here is an example, again using the <code>MyIntentReceiver</code> class:</p>
@@ -654,7 +654,8 @@
<td>A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be
included in the Intent as application data, with the key being the extra's name. For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>.
-There is no limit on the number of key/value pairs, though there is a limit on the total size of the message (4kb). Note that the values <em>must be enclosed by strings</em>. If you want to include objects or other non-string data types (such as integers or booleans), you have to do the conversion to string yourself. Also note that the key cannot be a reserved word ("from" or any word starting with "google."). Optional.</td>
+There is no limit on the number of key/value pairs, though there is a limit on the total size of the message (4kb). The values could be any JSON object, but we recommend using strings, since the values will be converted to strings in the GCM server anyway. If you want to include objects or other non-string data types (such as integers or booleans), you have to do the conversion to string yourself. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with <code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
+
</tr>
<tr>
@@ -686,7 +687,10 @@
</tr>
<tr>
<td><code>data.<key></code></td>
- <td>Payload data, expressed as parameters prefixed with <code>data.</code> and suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. There is no limit on the number of key/value parameters, though there is a limit on the total size of the message. Note that the key cannot be a reserved word ("from" or any word starting with "google."). Optional.</td>
+
+ <td>Payload data, expressed as parameters prefixed with <code>data.</code> and suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. There is no limit on the number of key/value parameters, though there is a limit on the total size of the message. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with
+<code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
+
</tr>
<tr>
<td><code>delay_while_idle</code></td>
@@ -817,7 +821,7 @@
<li>Otherwise, get the value of <code>error</code>:
<ul>
<li>If it is <code>Unavailable</code>, you could retry to send it in another request.</li>
- <li>If it is <code>NotRegistered</code>, you should remove the registration ID from your server database because the application was uninstalled from the device.</li>
+ <li>If it is <code>NotRegistered</code>, you should remove the registration ID from your server database because the application was uninstalled from the device or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
<li>Otherwise, there is something wrong in the registration ID passed in the request; it is probably a non-recoverable error that will also require removing the registration from the server database. See <a href="#error_codes">Interpreting an error response</a> for all possible error values.</li>
</ul>
</li>
@@ -851,6 +855,7 @@
<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
<dd>Check the formatting of the registration ID that you pass to the server. Make sure it matches the registration ID the phone receives in the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're not truncating it or adding additional characters.
<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
+
<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
<dd>A registration ID is tied to a certain group of senders. When an application registers for GCM usage, it must specify which senders are allowed to send messages. Make sure you're using one of those when trying to send messages to the device. If you switch to a different sender, the existing registration IDs won't work.
Happens when error code is <code>MismatchSenderId</code>.</dd>
@@ -861,15 +866,21 @@
<li>If the application manually unregisters by issuing a <span class="prettyprint pretty-java"><code>com.google.android.c2dm.intent.UNREGISTER</code></span><code> </code>intent.</li>
<li>If the application is automatically unregistered, which can happen (but is not guaranteed) if the user uninstalls the application.</li>
<li>If the registration ID expires. Google might decide to refresh registration IDs. </li>
+ <li>If the application is updated but the new version does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
</ul>
For all these cases, you should remove this registration ID from the 3rd-party server and stop using it to send
messages.
<br/>Happens when error code is <code>NotRegistered</code>.</dd>
- <dt id="big_msg"><strong>Message Too Big</strong></dt>
+<dt id="big_msg"><strong>Message Too Big</strong></dt>
<dd>The total size of the payload data that is included in a message can't exceed 4096 bytes. Note that this includes both the size of the keys as well as the values.
<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
+<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
+<dd>The payload data contains a key (such as <code>from</code> or any value prefixed by <code>google.</code>) that is used internally by GCM in the <code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used. Note that some words (such as <code>collapse_key</code>) are also used by GCM but are allowed in the payload, in which case the payload value will be overridden by the GCM value.
+<br />
+Happens when the error code is <code>InvalidDataKey</code>.</dd>
+
<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
<dd>The value for the Time to Live field must be an integer representing a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code is <code>InvalidTtl</code>.
</dd>
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 4b51994..2907f10 100755
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -29,6 +29,9 @@
import android.provider.MediaStore;
import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -582,7 +585,28 @@
if (null == path || path.equals("")) {
throw new IllegalArgumentException("Given path should be non null");
}
- return _getOriginalMimeType(mUniqueId, path);
+
+ String mime = null;
+
+ FileInputStream is = null;
+ try {
+ FileDescriptor fd = null;
+ File file = new File(path);
+ if (file.exists()) {
+ is = new FileInputStream(file);
+ fd = is.getFD();
+ }
+ mime = _getOriginalMimeType(mUniqueId, path, fd);
+ } catch (IOException ioe) {
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch(IOException e) {}
+ }
+ }
+
+ return mime;
}
/**
@@ -848,7 +872,7 @@
private native int _getDrmObjectType(int uniqueId, String path, String mimeType);
- private native String _getOriginalMimeType(int uniqueId, String path);
+ private native String _getOriginalMimeType(int uniqueId, String path, FileDescriptor fd);
private native int _checkRightsStatus(int uniqueId, String path, int action);
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index fb685a2..baddf62 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -587,22 +587,28 @@
}
static jstring android_drm_DrmManagerClient_getOriginalMimeType(
- JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
+ JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jobject fileDescriptor) {
ALOGV("getOriginalMimeType Enter");
+
+ int fd = (fileDescriptor == NULL)
+ ? -1
+ : jniGetFDFromFileDescriptor(env, fileDescriptor);
+
String8 mimeType
= getDrmManagerClientImpl(env, thiz)
- ->getOriginalMimeType(uniqueId, Utility::getStringValue(env, path));
+ ->getOriginalMimeType(uniqueId,
+ Utility::getStringValue(env, path), fd);
ALOGV("getOriginalMimeType Exit");
return env->NewStringUTF(mimeType.string());
}
static jint android_drm_DrmManagerClient_checkRightsStatus(
JNIEnv* env, jobject thiz, jint uniqueId, jstring path, int action) {
- ALOGV("getOriginalMimeType Enter");
+ ALOGV("checkRightsStatus Enter");
int rightsStatus
= getDrmManagerClientImpl(env, thiz)
->checkRightsStatus(uniqueId, Utility::getStringValue(env, path), action);
- ALOGV("getOriginalMimeType Exit");
+ ALOGV("checkRightsStatus Exit");
return rightsStatus;
}
@@ -730,7 +736,7 @@
{"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
(void*)android_drm_DrmManagerClient_getDrmObjectType},
- {"_getOriginalMimeType", "(ILjava/lang/String;)Ljava/lang/String;",
+ {"_getOriginalMimeType", "(ILjava/lang/String;Ljava/io/FileDescriptor;)Ljava/lang/String;",
(void*)android_drm_DrmManagerClient_getOriginalMimeType},
{"_checkRightsStatus", "(ILjava/lang/String;I)I",
diff --git a/graphics/java/android/renderscript/ScriptIntrinsic.java b/graphics/java/android/renderscript/ScriptIntrinsic.java
index 6ad1527..f275fee 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsic.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsic.java
@@ -28,8 +28,4 @@
ScriptIntrinsic(int id, RenderScript rs) {
super(id, rs);
}
-
- public void forEach(Allocation ain, Allocation aout) {
- forEach(0, ain, aout, null);
- }
}
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
index 0ae1449..c7465a7 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -32,6 +32,7 @@
**/
public class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic {
private float[] mValues = new float[9];
+ private Allocation mInput;
ScriptIntrinsicConvolve3x3(int id, RenderScript rs) {
super(id, rs);
@@ -52,8 +53,12 @@
}
+ public void setInput(Allocation ain) {
+ mInput = ain;
+ bindAllocation(ain, 1);
+ }
- public void setValues(float v[]) {
+ public void setColorMatrix(float v[]) {
FieldPacker fp = new FieldPacker(9*4);
for (int ct=0; ct < mValues.length; ct++) {
mValues[ct] = v[ct];
@@ -61,5 +66,10 @@
}
setVar(0, fp);
}
+
+ public void forEach(Allocation aout) {
+ forEach(0, null, aout, null);
+ }
+
}
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
new file mode 100644
index 0000000..c42001b
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2012 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.security;
+
+import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyPairGeneratorSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Provides a way to create instances of a KeyPair which will be placed in the
+ * Android keystore service usable only by the application that called it. This
+ * can be used in conjunction with
+ * {@link java.security.KeyStore#getInstance(String)} using the
+ * {@code "AndroidKeyStore"} type.
+ * <p>
+ * This class can not be directly instantiated and must instead be used via the
+ * {@link KeyPairGenerator#getInstance(String)
+ * KeyPairGenerator.getInstance("AndroidKeyPairGenerator")} API.
+ *
+ * {@hide}
+ */
+@SuppressWarnings("deprecation")
+public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
+ public static final String NAME = "AndroidKeyPairGenerator";
+
+ private android.security.KeyStore mKeyStore;
+
+ private AndroidKeyPairGeneratorSpec mSpec;
+
+ /**
+ * Generate a KeyPair which is backed by the Android keystore service. You
+ * must call {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
+ * with an {@link AndroidKeyPairGeneratorSpec} as the {@code params}
+ * argument before calling this otherwise an {@code IllegalStateException}
+ * will be thrown.
+ * <p>
+ * This will create an entry in the Android keystore service with a
+ * self-signed certificate using the {@code params} specified in the
+ * {@code initialize(params)} call.
+ *
+ * @throws IllegalStateException when called before calling
+ * {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
+ * @see java.security.KeyPairGeneratorSpi#generateKeyPair()
+ */
+ @Override
+ public KeyPair generateKeyPair() {
+ if (mKeyStore == null || mSpec == null) {
+ throw new IllegalStateException(
+ "Must call initialize with an AndroidKeyPairGeneratorSpec first");
+ }
+
+ final String alias = mSpec.getKeystoreAlias();
+
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+ mKeyStore.generate(privateKeyAlias);
+
+ final PrivateKey privKey;
+ final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+ try {
+ privKey = engine.getPrivateKeyById(privateKeyAlias);
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("Can't get key", e);
+ }
+
+ final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias);
+
+ final PublicKey pubKey;
+ try {
+ final KeyFactory keyFact = KeyFactory.getInstance("RSA");
+ pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Can't instantiate RSA key generator", e);
+ } catch (InvalidKeySpecException e) {
+ throw new IllegalStateException("keystore returned invalid key encoding", e);
+ }
+
+ final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+ certGen.setPublicKey(pubKey);
+ certGen.setSerialNumber(mSpec.getSerialNumber());
+ certGen.setSubjectDN(mSpec.getSubjectDN());
+ certGen.setIssuerDN(mSpec.getSubjectDN());
+ certGen.setNotBefore(mSpec.getStartDate());
+ certGen.setNotAfter(mSpec.getEndDate());
+ certGen.setSignatureAlgorithm("sha1WithRSA");
+
+ final X509Certificate cert;
+ try {
+ cert = certGen.generate(privKey);
+ } catch (Exception e) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+ throw new IllegalStateException("Can't generate certificate", e);
+ }
+
+ byte[] certBytes;
+ try {
+ certBytes = cert.getEncoded();
+ } catch (CertificateEncodingException e) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+ throw new IllegalStateException("Can't get encoding of certificate", e);
+ }
+
+ if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+ throw new IllegalStateException("Can't store certificate in AndroidKeyStore");
+ }
+
+ return new KeyPair(pubKey, privKey);
+ }
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator");
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ if (params == null) {
+ throw new InvalidAlgorithmParameterException(
+ "must supply params of type AndroidKeyPairGenericSpec");
+ } else if (!(params instanceof AndroidKeyPairGeneratorSpec)) {
+ throw new InvalidAlgorithmParameterException(
+ "params must be of type AndroidKeyPairGeneratorSpec");
+ }
+
+ AndroidKeyPairGeneratorSpec spec = (AndroidKeyPairGeneratorSpec) params;
+
+ mSpec = spec;
+ mKeyStore = android.security.KeyStore.getInstance();
+ }
+}
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
new file mode 100644
index 0000000..311359c
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 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.security;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * This provides the required parameters needed for initializing the KeyPair
+ * generator that works with
+ * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * facility</a>.
+ */
+public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
+ private final String mKeystoreAlias;
+
+ private final Context mContext;
+
+ private final X500Principal mSubjectDN;
+
+ private final BigInteger mSerialNumber;
+
+ private final Date mStartDate;
+
+ private final Date mEndDate;
+
+ /**
+ * Parameter specification for the "{@code AndroidKeyPairGenerator}"
+ * instance of the {@link java.security.KeyPairGenerator} API. The
+ * {@code context} passed in may be used to pop up some UI to ask the user
+ * to unlock or initialize the Android keystore facility.
+ * <p>
+ * After generation, the {@code keyStoreAlias} is used with the
+ * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
+ * interface to retrieve the {@link PrivateKey} and its associated
+ * {@link Certificate} chain.
+ * <p>
+ * The KeyPair generator will create a self-signed certificate with the
+ * properties of {@code subjectDN} as its X.509v3 Subject Distinguished Name
+ * and as its X.509v3 Issuer Distinguished Name, using the specified
+ * {@code serialNumber}, and the validity date starting at {@code startDate}
+ * and ending at {@code endDate}.
+ *
+ * @param context Android context for the activity
+ * @param keyStoreAlias name to use for the generated key in the Android
+ * keystore
+ * @param subjectDN X.509 v3 Subject Distinguished Name
+ * @param serialNumber X509 v3 certificate serial number
+ * @param startDate the start of the self-signed certificate validity period
+ * @param endDate the end date of the self-signed certificate validity
+ * period
+ * @throws IllegalArgumentException when any argument is {@code null} or
+ * {@code endDate} is before {@code startDate}.
+ */
+ public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
+ X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
+ if (context == null) {
+ throw new IllegalArgumentException("context == null");
+ } else if (TextUtils.isEmpty(keyStoreAlias)) {
+ throw new IllegalArgumentException("keyStoreAlias must not be empty");
+ } else if (subjectDN == null) {
+ throw new IllegalArgumentException("subjectDN == null");
+ } else if (serialNumber == null) {
+ throw new IllegalArgumentException("serialNumber == null");
+ } else if (startDate == null) {
+ throw new IllegalArgumentException("startDate == null");
+ } else if (endDate == null) {
+ throw new IllegalArgumentException("endDate == null");
+ } else if (endDate.before(startDate)) {
+ throw new IllegalArgumentException("endDate < startDate");
+ }
+
+ mContext = context;
+ mKeystoreAlias = keyStoreAlias;
+ mSubjectDN = subjectDN;
+ mSerialNumber = serialNumber;
+ mStartDate = startDate;
+ mEndDate = endDate;
+ }
+
+ /**
+ * @hide
+ */
+ String getKeystoreAlias() {
+ return mKeystoreAlias;
+ }
+
+ /**
+ * @hide
+ */
+ Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * @hide
+ */
+ X500Principal getSubjectDN() {
+ return mSubjectDN;
+ }
+
+ /**
+ * @hide
+ */
+ BigInteger getSerialNumber() {
+ return mSerialNumber;
+ }
+
+ /**
+ * @hide
+ */
+ Date getStartDate() {
+ return mStartDate;
+ }
+
+ /**
+ * @hide
+ */
+ Date getEndDate() {
+ return mEndDate;
+ }
+}
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index a629f8d..7b6e540 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -16,7 +16,9 @@
package android.security;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLDSAPrivateKey;
import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey;
import android.util.Log;
@@ -46,9 +48,8 @@
import java.util.Set;
/**
- * A java.security.KeyStore interface for the Android KeyStore. This class is
- * hidden from the Android API, but an instance of it can be created via the
- * {@link java.security.KeyStore#getInstance(String)
+ * A java.security.KeyStore interface for the Android KeyStore. An instance of
+ * it can be created via the {@link java.security.KeyStore#getInstance(String)
* KeyStore.getInstance("AndroidKeyStore")} interface. This returns a
* java.security.KeyStore backed by this "AndroidKeyStore" implementation.
* <p>
@@ -194,17 +195,41 @@
private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain)
throws KeyStoreException {
- // Make sure the PrivateKey format is the one we support.
- final String keyFormat = key.getFormat();
- if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
- throw new KeyStoreException(
- "Only PrivateKeys that can be encoded into PKCS#8 are supported");
+ byte[] keyBytes = null;
+
+ final String pkeyAlias;
+ if (key instanceof OpenSSLRSAPrivateKey) {
+ pkeyAlias = ((OpenSSLRSAPrivateKey) key).getPkeyAlias();
+ } else if (key instanceof OpenSSLDSAPrivateKey) {
+ pkeyAlias = ((OpenSSLDSAPrivateKey) key).getPkeyAlias();
+ } else {
+ pkeyAlias = null;
}
- // Make sure we can actually encode the key.
- final byte[] keyBytes = key.getEncoded();
- if (keyBytes == null) {
- throw new KeyStoreException("PrivateKey has no encoding");
+ final boolean shouldReplacePrivateKey;
+ if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
+ final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
+ if (!alias.equals(keySubalias)) {
+ throw new KeyStoreException("Can only replace keys with same alias: " + alias
+ + " != " + keySubalias);
+ }
+
+ shouldReplacePrivateKey = false;
+ } else {
+ // Make sure the PrivateKey format is the one we support.
+ final String keyFormat = key.getFormat();
+ if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
+ throw new KeyStoreException(
+ "Only PrivateKeys that can be encoded into PKCS#8 are supported");
+ }
+
+ // Make sure we can actually encode the key.
+ keyBytes = key.getEncoded();
+ if (keyBytes == null) {
+ throw new KeyStoreException("PrivateKey has no encoding");
+ }
+
+ shouldReplacePrivateKey = true;
}
// Make sure the chain exists since this is a PrivateKey
@@ -274,17 +299,25 @@
}
/*
- * Make sure we clear out all the types we know about before trying to
+ * Make sure we clear out all the appropriate types before trying to
* write.
*/
- deleteAllTypesForAlias(alias);
+ if (shouldReplacePrivateKey) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+ } else {
+ Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
+ }
- if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
+ if (shouldReplacePrivateKey
+ && !mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new KeyStoreException("Couldn't put private key in keystore");
} else if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new KeyStoreException("Couldn't put certificate #1 in keystore");
} else if (chainBytes != null
&& !mKeyStore.put(Credentials.CA_CERTIFICATE + alias, chainBytes)) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new KeyStoreException("Couldn't put certificate chain in keystore");
}
}
@@ -315,26 +348,11 @@
@Override
public void engineDeleteEntry(String alias) throws KeyStoreException {
- if (!deleteAllTypesForAlias(alias)) {
+ if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
throw new KeyStoreException("No such entry " + alias);
}
}
- /**
- * Delete all types (private key, certificate, CA certificate) for a
- * particular {@code alias}. All three can exist for any given alias.
- * Returns {@code true} if there was at least one of those types.
- */
- private boolean deleteAllTypesForAlias(String alias) {
- /*
- * Make sure every type is deleted. There can be all three types, so
- * don't use a conditional here.
- */
- return mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + alias)
- | mKeyStore.delete(Credentials.USER_CERTIFICATE + alias)
- | mKeyStore.delete(Credentials.CA_CERTIFICATE + alias);
- }
-
private Set<String> getUniqueAliases() {
final String[] rawAliases = mKeyStore.saw("");
if (rawAliases == null) {
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index df22f58..40d7e1a 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -29,6 +29,11 @@
public AndroidKeyStoreProvider() {
super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
+ // java.security.KeyStore
put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
+
+ // java.security.KeyPairGenerator
+ put("KeyPairGenerator." + AndroidKeyPairGenerator.NAME,
+ AndroidKeyPairGenerator.class.getName());
}
}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 68ba2b1..f6bf432 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -185,4 +185,32 @@
Log.w(LOGTAG, e.toString());
}
}
+
+ /**
+ * Delete all types (private key, certificate, CA certificate) for a
+ * particular {@code alias}. All three can exist for any given alias.
+ * Returns {@code true} if there was at least one of those types.
+ */
+ static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
+ /*
+ * Make sure every type is deleted. There can be all three types, so
+ * don't use a conditional here.
+ */
+ return keystore.delKey(Credentials.USER_PRIVATE_KEY + alias)
+ | deleteCertificateTypesForAlias(keystore, alias);
+ }
+
+ /**
+ * Delete all types (private key, certificate, CA certificate) for a
+ * particular {@code alias}. All three can exist for any given alias.
+ * Returns {@code true} if there was at least one of those types.
+ */
+ static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
+ /*
+ * Make sure every certificate type is deleted. There can be two types,
+ * so don't use a conditional here.
+ */
+ return keystore.delete(Credentials.USER_CERTIFICATE + alias)
+ | keystore.delete(Credentials.CA_CERTIFICATE + alias);
+ }
}
diff --git a/keystore/java/android/security/package.html b/keystore/java/android/security/package.html
new file mode 100644
index 0000000..610cbf0
--- /dev/null
+++ b/keystore/java/android/security/package.html
@@ -0,0 +1,9 @@
+<HTML>
+<BODY>
+ <p>Provides access to a few facilities of the Android security
+ subsystems.</p>
+ <p>For information on how to use this facility, see the <a
+ href="{@docRoot}guide/topics/security/keystore.html">Android
+ KeyStore facility</a> guide.</p>
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
index 95604c6..61cf640 100644
--- a/keystore/tests/Android.mk
+++ b/keystore/tests/Android.mk
@@ -5,7 +5,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
new file mode 100644
index 0000000..e6a3750
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 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.security;
+
+import android.test.AndroidTestCase;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class AndroidKeyPairGeneratorSpecTest extends AndroidTestCase {
+ private static final String TEST_ALIAS_1 = "test1";
+
+ private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+ private static final long NOW_MILLIS = System.currentTimeMillis();
+
+ private static final BigInteger SERIAL_1 = BigInteger.ONE;
+
+ /* We have to round this off because X509v3 doesn't store milliseconds. */
+ private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+ @SuppressWarnings("deprecation")
+ private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
+ public void testConstructor_Success() throws Exception {
+ AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec(getContext(),
+ TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, NOW_PLUS_10_YEARS);
+
+ assertEquals("Context should be the one specified", getContext(), spec.getContext());
+
+ assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
+
+ assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
+
+ assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
+
+ assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
+ }
+
+ public void testConstructor_NullContext_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ fail("Should throw IllegalArgumentException when context is null");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testConstructor_NullKeystoreAlias_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ fail("Should throw IllegalArgumentException when keystoreAlias is null");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testConstructor_NullSubjectDN_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ fail("Should throw IllegalArgumentException when subjectDN is null");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testConstructor_NullSerial_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW,
+ NOW_PLUS_10_YEARS);
+ fail("Should throw IllegalArgumentException when startDate is null");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testConstructor_NullStartDate_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null,
+ NOW_PLUS_10_YEARS);
+ fail("Should throw IllegalArgumentException when startDate is null");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testConstructor_NullEndDate_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+ null);
+ fail("Should throw IllegalArgumentException when keystoreAlias is null");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testConstructor_EndBeforeStart_Failure() throws Exception {
+ try {
+ new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
+ NOW_PLUS_10_YEARS, NOW);
+ fail("Should throw IllegalArgumentException when end is before start");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+}
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
new file mode 100644
index 0000000..d108caaa
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 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.security;
+
+import android.test.AndroidTestCase;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
+ private android.security.KeyStore mAndroidKeyStore;
+
+ private java.security.KeyPairGenerator mGenerator;
+
+ private static final String TEST_ALIAS_1 = "test1";
+
+ private static final String TEST_ALIAS_2 = "test2";
+
+ private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+ private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
+
+ private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
+
+ private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
+
+ private static final long NOW_MILLIS = System.currentTimeMillis();
+
+ /* We have to round this off because X509v3 doesn't store milliseconds. */
+ private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+ @SuppressWarnings("deprecation")
+ private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
+ @Override
+ protected void setUp() throws Exception {
+ mAndroidKeyStore = android.security.KeyStore.getInstance();
+
+ assertTrue(mAndroidKeyStore.reset());
+
+ assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state());
+
+ assertTrue(mAndroidKeyStore.password("1111"));
+
+ assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state());
+
+ assertEquals(0, mAndroidKeyStore.saw("").length);
+
+ mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
+ }
+
+ public void testKeyPairGenerator_Initialize_Params_Success() throws Exception {
+ mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+ TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+ }
+
+ public void testKeyPairGenerator_Initialize_KeySize_Failure() throws Exception {
+ try {
+ mGenerator.initialize(1024);
+ fail("KeyPairGenerator should not support setting the key size");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Failure() throws Exception {
+ try {
+ mGenerator.initialize(1024, new SecureRandom());
+ fail("KeyPairGenerator should not support setting the key size");
+ } catch (IllegalArgumentException success) {
+ }
+ }
+
+ public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Failure() throws Exception {
+ mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+ TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS), new SecureRandom());
+ }
+
+ public void testKeyPairGenerator_GenerateKeyPair_Success() throws Exception {
+ mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+ TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+
+ final KeyPair pair = mGenerator.generateKeyPair();
+ assertNotNull("The KeyPair returned should not be null", pair);
+
+ assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS);
+ }
+
+ public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception {
+ // Generate the first key
+ {
+ mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+ TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+ final KeyPair pair1 = mGenerator.generateKeyPair();
+ assertNotNull("The KeyPair returned should not be null", pair1);
+ assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ }
+
+ // Replace the original key
+ {
+ mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_2,
+ TEST_DN_2, TEST_SERIAL_2, NOW, NOW_PLUS_10_YEARS));
+ final KeyPair pair2 = mGenerator.generateKeyPair();
+ assertNotNull("The KeyPair returned should not be null", pair2);
+ assertKeyPairCorrect(pair2, TEST_ALIAS_2, TEST_DN_2, TEST_SERIAL_2, NOW,
+ NOW_PLUS_10_YEARS);
+ }
+ }
+
+ private void assertKeyPairCorrect(KeyPair pair, String alias, X500Principal dn,
+ BigInteger serial, Date start, Date end) throws Exception {
+ final PublicKey pubKey = pair.getPublic();
+ assertNotNull("The PublicKey for the KeyPair should be not null", pubKey);
+
+ final PrivateKey privKey = pair.getPrivate();
+ assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
+
+ final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+ assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
+
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ final Certificate userCert = cf
+ .generateCertificate(new ByteArrayInputStream(userCertBytes));
+
+ assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
+
+ final X509Certificate x509userCert = (X509Certificate) userCert;
+
+ assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
+ pubKey, x509userCert.getPublicKey());
+
+ assertEquals("The Subject DN should be the one passed into the params", dn,
+ x509userCert.getSubjectDN());
+
+ assertEquals("The Issuer DN should be the same as the Subject DN", dn,
+ x509userCert.getIssuerDN());
+
+ assertEquals("The Serial should be the one passed into the params", serial,
+ x509userCert.getSerialNumber());
+
+ assertEquals("The notBefore date should be the one passed into the params", start,
+ x509userCert.getNotBefore());
+
+ assertEquals("The notAfter date should be the one passed into the params", end,
+ x509userCert.getNotAfter());
+
+ x509userCert.verify(pubKey);
+
+ final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+ assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
+
+ final byte[] pubKeyBytes = mAndroidKeyStore.getPubkey(Credentials.USER_PRIVATE_KEY + alias);
+ assertNotNull("The keystore should return the public key for the generated key",
+ pubKeyBytes);
+ }
+}
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index bff01b8..49e2f12 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -16,12 +16,17 @@
package android.security;
+import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore.Entry;
@@ -30,12 +35,14 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
@@ -44,6 +51,8 @@
import java.util.Iterator;
import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
public class AndroidKeyStoreTest extends AndroidTestCase {
private android.security.KeyStore mAndroidKeyStore;
@@ -55,6 +64,22 @@
private static final String TEST_ALIAS_3 = "test3";
+ private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+ private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
+
+ private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
+
+ private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
+
+ private static final long NOW_MILLIS = System.currentTimeMillis();
+
+ /* We have to round this off because X509v3 doesn't store milliseconds. */
+ private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+ @SuppressWarnings("deprecation")
+ private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
/*
* The keys and certificates below are generated with:
*
@@ -759,17 +784,31 @@
assertPrivateKeyEntryEquals(keyEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
}
+ @SuppressWarnings("unchecked")
private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, byte[] key, byte[] cert,
byte[] ca) throws Exception {
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(key));
- assertEquals("Returned PrivateKey should be what we inserted", expectedKey,
- keyEntry.getPrivateKey());
-
CertificateFactory certFact = CertificateFactory.getInstance("X.509");
Certificate expectedCert = certFact.generateCertificate(new ByteArrayInputStream(cert));
+ final Collection<Certificate> expectedChain;
+ if (ca != null) {
+ expectedChain = (Collection<Certificate>) certFact
+ .generateCertificates(new ByteArrayInputStream(ca));
+ } else {
+ expectedChain = null;
+ }
+
+ assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, expectedChain);
+ }
+
+ private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
+ Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
+ assertEquals("Returned PrivateKey should be what we inserted", expectedKey,
+ keyEntry.getPrivateKey());
+
assertEquals("Returned Certificate should be what we inserted", expectedCert,
keyEntry.getCertificate());
@@ -777,13 +816,9 @@
assertEquals("First certificate in chain should be user cert", expectedCert, actualChain[0]);
- if (ca == null) {
+ if (expectedChain == null) {
assertEquals("Certificate chain should not include CAs", 1, actualChain.length);
} else {
- @SuppressWarnings("unchecked")
- Collection<Certificate> expectedChain = (Collection<Certificate>) certFact
- .generateCertificates(new ByteArrayInputStream(ca));
-
int i = 1;
final Iterator<Certificate> it = expectedChain.iterator();
while (it.hasNext()) {
@@ -1306,6 +1341,142 @@
}
}
+ @SuppressWarnings("deprecation")
+ private static X509Certificate generateCertificate(android.security.KeyStore keyStore,
+ String alias, BigInteger serialNumber, X500Principal subjectDN, Date notBefore,
+ Date notAfter) throws Exception {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+
+ final PrivateKey privKey;
+ final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+ try {
+ privKey = engine.getPrivateKeyById(privateKeyAlias);
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("Can't get key", e);
+ }
+
+ final byte[] pubKeyBytes = keyStore.getPubkey(privateKeyAlias);
+
+ final PublicKey pubKey;
+ try {
+ final KeyFactory keyFact = KeyFactory.getInstance("RSA");
+ pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Can't instantiate RSA key generator", e);
+ } catch (InvalidKeySpecException e) {
+ throw new IllegalStateException("keystore returned invalid key encoding", e);
+ }
+
+ final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+ certGen.setPublicKey(pubKey);
+ certGen.setSerialNumber(serialNumber);
+ certGen.setSubjectDN(subjectDN);
+ certGen.setIssuerDN(subjectDN);
+ certGen.setNotBefore(notBefore);
+ certGen.setNotAfter(notAfter);
+ certGen.setSignatureAlgorithm("sha1WithRSA");
+
+ final X509Certificate cert = certGen.generate(privKey);
+
+ return cert;
+ }
+
+ public void testKeyStore_SetKeyEntry_ReplacedChain_Success() throws Exception {
+ mKeyStore.load(null, null);
+
+ // Create key #1
+ {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
+ assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+
+ Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
+
+ assertTrue(key instanceof PrivateKey);
+
+ PrivateKey expectedKey = (PrivateKey) key;
+
+ X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
+ TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
+
+ assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
+ expectedCert.getEncoded()));
+
+ Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+
+ assertTrue(entry instanceof PrivateKeyEntry);
+
+ PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+
+ assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null);
+ }
+
+ // Replace key #1 with new chain
+ {
+ Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
+
+ assertTrue(key instanceof PrivateKey);
+
+ PrivateKey expectedKey = (PrivateKey) key;
+
+ X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
+ TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
+
+ mKeyStore.setKeyEntry(TEST_ALIAS_1, expectedKey, null,
+ new Certificate[] { expectedCert });
+
+ Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+
+ assertTrue(entry instanceof PrivateKeyEntry);
+
+ PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+
+ assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null);
+ }
+ }
+
+ public void testKeyStore_SetKeyEntry_ReplacedChain_DifferentPrivateKey_Failure()
+ throws Exception {
+ mKeyStore.load(null, null);
+
+ // Create key #1
+ {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
+ assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+
+ X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
+ TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
+
+ assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
+ cert.getEncoded()));
+ }
+
+ // Create key #2
+ {
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2;
+ assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
+
+ X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
+ TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
+
+ assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_2,
+ cert.getEncoded()));
+ }
+
+ // Replace key #1 with key #2
+ {
+ Key key1 = mKeyStore.getKey(TEST_ALIAS_2, null);
+
+ X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
+ TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
+
+ try {
+ mKeyStore.setKeyEntry(TEST_ALIAS_1, key1, null, new Certificate[] { cert });
+ fail("Should not allow setting of KeyEntry with wrong PrivaetKey");
+ } catch (KeyStoreException success) {
+ }
+ }
+ }
+
public void testKeyStore_Size_Success() throws Exception {
mKeyStore.load(null, null);
diff --git a/location/java/com/android/internal/location/ProviderProperties.java b/location/java/com/android/internal/location/ProviderProperties.java
index 08aed80..def96f0 100644
--- a/location/java/com/android/internal/location/ProviderProperties.java
+++ b/location/java/com/android/internal/location/ProviderProperties.java
@@ -145,7 +145,7 @@
parcel.writeInt(mHasMonetaryCost ? 1 : 0);
parcel.writeInt(mSupportsAltitude ? 1 : 0);
parcel.writeInt(mSupportsSpeed ? 1 : 0);
- parcel.writeInt(mSupportsSpeed ? 1 : 0);
+ parcel.writeInt(mSupportsBearing ? 1 : 0);
parcel.writeInt(mPowerRequirement);
parcel.writeInt(mAccuracy);
}
diff --git a/media/java/android/media/DataSource.java b/media/java/android/media/DataSource.java
new file mode 100644
index 0000000..347bd5f
--- /dev/null
+++ b/media/java/android/media/DataSource.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 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.media;
+
+import java.io.Closeable;
+
+/**
+ * An abstraction for a media data source, e.g. a file or an http stream
+ * {@hide}
+ */
+public interface DataSource extends Closeable {
+ /**
+ * Reads data from the data source at the requested position
+ *
+ * @param offset where in the source to read
+ * @param buffer the buffer to read the data into
+ * @param size how many bytes to read
+ * @return the number of bytes read, or -1 if there was an error
+ */
+ public int readAt(long offset, byte[] buffer, int size);
+
+ /**
+ * Gets the size of the data source.
+ *
+ * @return size of data source, or -1 if the length is unknown
+ */
+ public long getSize();
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 687d3a5..4b8d3cb 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -22,6 +22,7 @@
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.net.Uri;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -60,6 +61,12 @@
}
/**
+ * Sets the DataSource object to be used as the data source for this extractor
+ * {@hide}
+ */
+ public native final void setDataSource(DataSource source);
+
+ /**
* Sets the data source as a content Uri.
*
* @param context the Context to use when resolving the Uri
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1b98109..ef0da3a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2265,6 +2265,16 @@
*/
public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
+ /** File or network related operation errors. */
+ public static final int MEDIA_ERROR_IO = -1004;
+ /** Bitstream is not conforming to the related coding standard or file spec. */
+ public static final int MEDIA_ERROR_MALFORMED = -1007;
+ /** Bitstream is conforming to the related coding standard or file spec, but
+ * the media framework does not support the feature. */
+ public static final int MEDIA_ERROR_UNSUPPORTED = -1010;
+ /** Some operation takes too long to complete, usually more than 3-5 seconds. */
+ public static final int MEDIA_ERROR_TIMED_OUT = -110;
+
/**
* Interface definition of a callback to be invoked when there
* has been an error during an asynchronous operation (other errors
@@ -2283,6 +2293,12 @@
* </ul>
* @param extra an extra code, specific to the error. Typically
* implementation dependent.
+ * <ul>
+ * <li>{@link #MEDIA_ERROR_IO}
+ * <li>{@link #MEDIA_ERROR_MALFORMED}
+ * <li>{@link #MEDIA_ERROR_UNSUPPORTED}
+ * <li>{@link #MEDIA_ERROR_TIMED_OUT}
+ * </ul>
* @return True if the method handled the error, false if it didn't.
* Returning false, or not having an OnErrorListener at all, will
* cause the OnCompletionListener to be called.
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 351ff04..23949fa 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -44,6 +44,72 @@
static fields_t gFields;
+class JavaDataSourceBridge : public DataSource {
+ jmethodID mReadMethod;
+ jmethodID mGetSizeMethod;
+ jmethodID mCloseMethod;
+ jobject mDataSource;
+ public:
+ JavaDataSourceBridge(JNIEnv *env, jobject source) {
+ mDataSource = env->NewGlobalRef(source);
+
+ jclass datasourceclass = env->GetObjectClass(mDataSource);
+ CHECK(datasourceclass != NULL);
+
+ mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
+ CHECK(mReadMethod != NULL);
+
+ mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
+ CHECK(mGetSizeMethod != NULL);
+
+ mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
+ CHECK(mCloseMethod != NULL);
+ }
+
+ ~JavaDataSourceBridge() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mDataSource, mCloseMethod);
+ env->DeleteGlobalRef(mDataSource);
+ }
+
+ virtual status_t initCheck() const {
+ return OK;
+ }
+
+ virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ // XXX could optimize this by reusing the same array
+ jbyteArray byteArrayObj = env->NewByteArray(size);
+ env->DeleteLocalRef(env->GetObjectClass(mDataSource));
+ env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
+ ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, size);
+ env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
+ env->DeleteLocalRef(byteArrayObj);
+ if (env->ExceptionCheck()) {
+ ALOGW("Exception occurred while reading %d at %lld", size, offset);
+ LOGW_EX(env);
+ env->ExceptionClear();
+ return -1;
+ }
+ return numread;
+ }
+
+ virtual status_t getSize(off64_t *size) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ CHECK(size != NULL);
+
+ int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
+ if (len < 0) {
+ *size = ERROR_UNSUPPORTED;
+ } else {
+ *size = len;
+ }
+ return OK;
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
@@ -76,6 +142,10 @@
return mImpl->setDataSource(fd, offset, size);
}
+status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
+ return mImpl->setDataSource(datasource);
+}
+
size_t JMediaExtractor::countTracks() const {
return mImpl->countTracks();
}
@@ -625,6 +695,33 @@
}
}
+static void android_media_MediaExtractor_setDataSourceCallback(
+ JNIEnv *env, jobject thiz,
+ jobject callbackObj) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (callbackObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
+ status_t err = extractor->setDataSource(bridge);
+
+ if (err != OK) {
+ jniThrowException(
+ env,
+ "java/io/IOException",
+ "Failed to instantiate extractor.");
+ return;
+ }
+}
+
static jlong android_media_MediaExtractor_getCachedDurationUs(
JNIEnv *env, jobject thiz) {
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -713,6 +810,9 @@
{ "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
(void *)android_media_MediaExtractor_setDataSourceFd },
+ { "setDataSource", "(Landroid/media/DataSource;)V",
+ (void *)android_media_MediaExtractor_setDataSourceCallback },
+
{ "getCachedDuration", "()J",
(void *)android_media_MediaExtractor_getCachedDurationUs },
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 2d4627e..03900db 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -19,6 +19,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/DataSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -39,6 +40,7 @@
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, off64_t offset, off64_t size);
+ status_t setDataSource(const sp<DataSource> &source);
size_t countTracks() const;
status_t getTrackFormat(size_t index, jobject *format) const;
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index a28b8a4..b36bd55 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -26,6 +26,7 @@
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.IPackageManager;
import android.content.pm.LimitedLengthInputStream;
+import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
@@ -181,6 +182,7 @@
}
ret.packageName = pkg.packageName;
+ ret.versionCode = pkg.versionCode;
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
@@ -268,12 +270,14 @@
if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) {
IPackageManager pm = IPackageManager.Stub.asInterface(
ServiceManager.getService("package"));
- String pkg = null;
+ PackageCleanItem pkg = null;
try {
while ((pkg=pm.nextPackageToClean(pkg)) != null) {
- eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg));
- eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg));
- eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg));
+ eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg.packageName));
+ eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg.packageName));
+ if (pkg.andCode) {
+ eraseFiles(Environment.getExternalStorageAppObbDirectory(pkg.packageName));
+ }
}
} catch (RemoteException e) {
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index a9de51f..9a80090 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -157,6 +157,8 @@
<bool name="def_screensaver_enabled">true</bool>
<!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_DOCK) -->
<bool name="def_screensaver_activate_on_dock">true</bool>
+ <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_SLEEP) -->
+ <bool name="def_screensaver_activate_on_sleep">true</bool>
<!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
<string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 1481eb2..db81786 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1131,7 +1131,11 @@
R.bool.def_screensaver_enabled);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
R.bool.def_screensaver_activate_on_dock);
- loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENT,
+ loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ R.bool.def_screensaver_activate_on_sleep);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+ R.string.def_screensaver_component);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
R.string.def_screensaver_component);
db.setTransactionSuccessful();
} finally {
@@ -1746,7 +1750,11 @@
R.bool.def_screensaver_enabled);
loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
R.bool.def_screensaver_activate_on_dock);
- loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENT,
+ loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ R.bool.def_screensaver_activate_on_sleep);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
+ R.string.def_screensaver_component);
+ loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
R.string.def_screensaver_component);
} finally {
if (stmt != null) stmt.close();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2eee31d..b185471 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -53,6 +53,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application
+ android:name="com.android.systemui.SystemUIApplication"
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
@@ -96,6 +97,16 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name=".recent.RecentsActivity"
+ android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.systemui.TOGGLE_RECENTS" />
+ </intent-filter>
+ </activity>
+
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"
@@ -168,5 +179,17 @@
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
</intent-filter>
</activity>
+
+ <!-- Beans in space -->
+ <service
+ android:name=".BeanBagDream"
+ android:exported="true"
+ android:label="Beans in space">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.DREAM" />
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 84e6bc8..6ae32f1 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 782d214..fdc56bb 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index a00bc5b..ea7c4e3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index 8605701..49d5101 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 38bd0cd..33e56e8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 0c12c16..2fb191d 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 477df5f..ce008f3 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index bd60cd6..b971088 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index 5272c91..d2d7842 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 00e3e27..2df9f6c 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -26,11 +26,6 @@
android:layout_width="match_parent"
systemui:recentItemLayout="@layout/status_bar_recent_item"
>
- <View
- android:id="@+id/recents_transition_background"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/status_bar_recents_background"
@@ -40,12 +35,6 @@
android:clipToPadding="false"
android:clipChildren="false">
- <ImageView
- android:id="@+id/recents_transition_placeholder_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
-
<com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index cb32d63..8eff1f4 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -27,7 +27,6 @@
android:background="@drawable/notification_panel_bg"
android:paddingTop="@dimen/notification_panel_padding_top"
android:layout_marginLeft="@dimen/notification_panel_margin_left"
- android:animateLayoutChanges="true"
>
<TextView
@@ -80,18 +79,10 @@
</ScrollView>
</LinearLayout>
- <LinearLayout android:id="@+id/handle"
+ <View android:id="@+id/handle"
android:layout_width="match_parent"
android:layout_height="@dimen/close_handle_height"
android:layout_gravity="bottom"
- android:orientation="vertical"
- >
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="@dimen/close_handle_height"
- android:layout_gravity="bottom"
- android:scaleType="fitXY"
- android:src="@drawable/status_bar_close"
- />
- </LinearLayout>
+ />
+
</com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index a7e5db1..7335f86 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -26,11 +26,6 @@
android:layout_width="match_parent"
systemui:recentItemLayout="@layout/status_bar_recent_item"
>
- <View
- android:id="@+id/recents_transition_background"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/status_bar_recents_background"
@@ -38,12 +33,6 @@
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
- <ImageView
- android:id="@+id/recents_transition_placeholder_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
-
<com.android.systemui.recent.RecentsVerticalScrollView
android:id="@+id/recents_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index 127551d..3951bba 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -28,11 +28,6 @@
android:clipChildren="false"
systemui:recentItemLayout="@layout/system_bar_recent_item"
>
- <View
- android:id="@+id/recents_transition_background"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/recents_bg_protect_tile"
@@ -42,11 +37,6 @@
android:layout_marginBottom="@*android:dimen/system_bar_height"
android:clipToPadding="false"
android:clipChildren="false">
- <ImageView
- android:id="@+id/recents_transition_placeholder_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
<com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b63ed4a..d5e4c0a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Sien"</string>
<string name="always_use_device" msgid="1450287437017315906">"Gebruik by verstek vir hierdie USB-toestel"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Gebruik by verstek vir hierdie USB-toebehoorsel"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Moet USB-ontfouting toegelaat word?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Moet USB-ontfouting van hierdie rekenaar af toegelaat word?"\n"Jou RSA-sleutelvingerafdruk is"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Laat altyd hierdie rekenaar toe"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoem om skerm te vul"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Strek om skerm te vul"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Versoenbaarheidszoem"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0d41cc7..f34ed8e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -56,11 +56,11 @@
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ምንም የተጫኑ መተግበሪያዎች ከዚህ የUSB ተቀጥላ ጋር አይሰሩም። በ<xliff:g id="URL">%1$s</xliff:g> ስለዚህ ተቀጥላ የበለጠ ለመረዳት።"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"የUSB ተቀጥላ"</string>
<string name="label_view" msgid="6304565553218192990">"ዕይታ"</string>
- <string name="always_use_device" msgid="1450287437017315906">"ለዚህ USB መሣሪያ በነባሪነት ተጠቀም"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"ለዚህ USB ተቀጥላ በነባሪነት ተጠቀም"</string>
+ <string name="always_use_device" msgid="1450287437017315906">"ለእዚህ USB መሣሪያ በነባሪነት ተጠቀም"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"ለእዚህ USB ተቀጥላ በነባሪነት ተጠቀም"</string>
<string name="usb_debugging_title" msgid="1114766024068112429">"የUSB ማረሚያ ይፈቀድ?"</string>
<string name="usb_debugging_message" msgid="719863946976291180">"የUSB ማረም ከዚህ ኮምፒውተር ይፈቀድ?"\n"የእርስዎ RSA ቁልፍ ጣት አሻራ "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g> ነው"</string>
- <string name="usb_debugging_always" msgid="4253099426793114693">"ለዚህ ኮምፒውተር ሁልጊዜ ፍቀድ"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"ለእዚህ ኮምፒውተር ሁልጊዜ ፍቀድ"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ማያ እንዲሞላ አጉላ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ማያ ለመሙለት ሳብ"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"የተኳኋኝነት አጉላ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d3d4c7f..6540f0a 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"عرض"</string>
<string name="always_use_device" msgid="1450287437017315906">"الاستخدام بشكل افتراضي لجهاز USB هذا"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"الاستخدام بشكل افتراضي لملحق USB هذا"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"هل تريد السماح بتصحيح أخطاء USB؟"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"هل تريد السماح بتصحيح أخطاء USB من هذا الكمبيوتر؟"\n"ملفك المرجعي لمفتاح RSA هو"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"السماح لهذا الكمبيوتر دومًا"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"تكبير/تصغير لملء الشاشة"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"توسيع بملء الشاشة"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"تكبير/تصغير التوافق"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ba57e91..56b8bb3 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Преглед"</string>
<string name="always_use_device" msgid="1450287437017315906">"Използване по подразб. за това USB устройство"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Използване по подразб. за този аксесоар за USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Да се разреши ли отстраняването на грешки през USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Да се разреши ли отстраняването на грешки през USB от този компютър?"\n"Отпечатъкът на вашия RSA ключ е"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Този компютър винаги да е разрешен"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Мащаб – запълва екрана"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Разпъване – запълва екрана"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Промяна на мащаба за съвместимост"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index fb6584e..a7bf519 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Zobrazit"</string>
<string name="always_use_device" msgid="1450287437017315906">"Pro toto zařízení USB použít jako výchozí"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Pro toto periferní zařízení USB použít jako výchozí"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Povolit ladění USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Povolit ladění USB z tohoto počítače?"\n"Váš digitální otisk klíče RSA je"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Vždy povolit tento počítač."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Přiblížit na celou obrazovku"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Na celou obrazovku"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Úprava velikosti z důvodu kompatibility"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4c07d9f..e0aa3f9 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
<string name="always_use_device" msgid="1450287437017315906">"Se usa de forma predeterminada para este dispositivo USB."</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Se usa de forma predeterminada para este accesorio USB."</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"¿Permitir la depuración de USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"¿Quieres permitir la depuración de USB desde esta computadora?"\n"La huella digital de tu clave RSA es"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>."</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Permitir el uso de esta computadora siempre"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ocupar la pantalla"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Estirar p/ ocupar la pantalla"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidad"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 17484377..4348bda 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Kuva"</string>
<string name="always_use_device" msgid="1450287437017315906">"Kasuta vaikimisi selle USB-seadme jaoks"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Vaikimisi kasuta seda USB-lisaseadet"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Kas lubada USB-silumine?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Kas lubada USB-silumine sellest arvutist?"\n"Teie RSA-võtme sõrmejälg on"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Luba alati see arvuti"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Suumi ekraani täitmiseks"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Venita ekraani täitmiseks"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Sobivussuum"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e75d5f0..66d65d9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"مشاهده"</string>
<string name="always_use_device" msgid="1450287437017315906">"استفاده به صورت پیشفرض برای این دستگاه USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"استفاده به صورت پیشفرض برای این دستگاه USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"اشکالزدایی USB انجام شود؟"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"اشکالزدایی USB از این رایانه مجاز باشد؟"\n"اثر انگشت کلید RSA شما"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"این رایانه همیشه مجاز است"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"بزرگنمایی برای پر کردن صفحه"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"بزرگنمایی سازگاری"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d862df8..18f8c9d 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Afficher"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utiliser par défaut pour ce périphérique USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Autoriser le débogage USB ?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Autoriser le débogage USB via cet ordinateur ?"\n"Votre empreinte de clé RSA est "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>."</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Toujours autoriser cet ordinateur"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Étirer pour remplir l\'écran"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilité"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b45b4ce..16e1443 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"देखें"</string>
<string name="always_use_device" msgid="1450287437017315906">"इस USB उपकरण के लिए डिफ़ॉल्ट रूप से उपयोग करें"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"इस USB एसेसरी के लिए डिफ़ॉल्ट रूप से उपयोग करें"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USB डीबग करने दें?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"इस कंप्यूटर से USB डीबग करने दें?"\n"आपका RSA कुंजी फ़िंगरप्रिंट यह है:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"इस कंप्यूटर को हमेशा अनुमति दें"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"स्क्रीन भरने हेतु ज़ूम करें"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"स्क्रीन को भरने के लिए खींचें"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"संगतता ज़ूम"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 620e193..830b73c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
<string name="always_use_device" msgid="1450287437017315906">"Koristi se prema zadanim postavkama za ovaj USB uređaj"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Koristi se prema zadanim postavkama za ovaj USB pribor"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Omogućiti rješavanje programske pogreške na USB-u?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Omogućiti rješavanje programske pogreške na USB-u na ovom računalu?"\n"Vaš je otisak prsta RSA ključa"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Uvijek dopusti ovom računalu"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj i ispuni zaslon"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rastegni i ispuni zaslon"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilno zumiranje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 1805ce0..4d49939 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Megtekintés"</string>
<string name="always_use_device" msgid="1450287437017315906">"Alapértelmezett használat ehhez az USB-eszközhöz"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Alapértelmezett használat ehhez az USB-kiegészítőhöz"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Engedélyezi az USB hibakeresést?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Engedélyezi az USB hibakeresést erről a számítógépről?"\n"Az Ön RSA-kulcs ujjlenyomata"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Mindig legyen engedélyezve ezen a számítógépen"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Nagyítás a kitöltéshez"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Nyújtás kitöltéshez"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilitás -- nagyítás/kicsinyítés"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8eda13f..a9fe4ae 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"表示"</string>
<string name="always_use_device" msgid="1450287437017315906">"このUSBデバイスにデフォルトで使用する"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"このUSBアクセサリにデフォルトで使用する"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USBデバッグを許可しますか?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"このパソコンからのUSBデバッグを許可しますか?"\n"RSAキーのフィンガープリントは次のとおりです"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"このパソコンを常に許可する"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"互換ズーム"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9562237..bd1cf03 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"보기"</string>
<string name="always_use_device" msgid="1450287437017315906">"이 USB 기기에 기본값으로 사용"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"이 USB 액세서리에 기본값으로 사용"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USB 디버깅을 허용하시겠습니까?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"이 컴퓨터에서 USB 디버깅을 허용하시겠습니까?"\n"귀하의 RSA 키 지문 파일은 다음과 같습니다."\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"이 컴퓨터에서 항상 허용"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"전체화면 모드로 확대"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"전체화면 모드로 확대"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"호환성 확대/축소"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index daacca55..a5a11e2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Žiūrėti"</string>
<string name="always_use_device" msgid="1450287437017315906">"Šiam USB įreng. naudoti pagal numat. nustatymus"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Šiam USB priedui naudoti pagal numat. nustatymus"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Leisti derinti USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Leisti derinti USB šiuo kompiuteriu?"\n"RSA rakto kontrolinis kodas yra"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Visada leisti šį kompiuterį"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Keisti mast., kad atit. ekr."</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ištempti, kad atit. ekr."</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Suderinamumo mastelio keitimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b189fd2..c18b03f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Skatīt"</string>
<string name="always_use_device" msgid="1450287437017315906">"Pēc noklusējuma izmantot šai USB ierīcei"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Pēc noklusējuma izmantot šim USB piederumam"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Vai atļaut USB atkļūdošanu?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Vai atļaut USB atkļūdošanu no šī datora?"\n"Jūsu RSA atslēgas identifikators ir"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Vienmēr atļaut no šī datora"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Tālumm., lai aizp. ekr."</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Stiepiet, lai aizp. ekr."</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Saderības tālummaiņa"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8da9ed5..ef926ac 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Lihat"</string>
<string name="always_use_device" msgid="1450287437017315906">"Gunakan secara lalai untuk peranti USB ini"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara lalai untuk aksesori USB ini"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Benarkan penyahpepijatan USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Benarkan Penyahpepijatan USB dari komputer ini?"\n"Cap jari kunci RSA anda ialah"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Sentiasa benarkan komputer ini"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zum untuk memenuhi skrin"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Regang utk memenuhi skrin"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zum keserasian"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 50d5e3b..7639c84 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Wyświetl"</string>
<string name="always_use_device" msgid="1450287437017315906">"Używaj domyślnie dla tego urządzenia USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Używaj domyślnie dla tego akcesorium USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Zezwalać na debugowanie USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Zezwalać na debugowanie USB z tego komputera?"\n"Twój odcisk cyfrowy klucza RSA to"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Zawsze zezwalaj dla tego komputera"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Powiększ, aby wypełnić ekran"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rozciągnij, aby wypełnić ekran"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Powiększenie w trybie zgodności"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b583aea..4b41ca0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Ver"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utilizar por predefinição para este aparelho USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utilizar por predefinição para este acessório USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Permitir Depuração USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Permitir a Depuração USB a partir deste computador?"\n"A sua pegada digital da chave RSA é"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Permitir sempre este computador"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom para preencher o ecrã"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Esticar p. caber em ec. int."</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidade"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index bae61d0..b88e096 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Visualizar"</string>
<string name="always_use_device" msgid="1450287437017315906">"Usar por padrão para este dispositivo USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Permitir a depuração USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Permitir a depuração USB a partir deste computador?"\n"A impressão digital de sua chave RSA é"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Sempre permitir este computador"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom p/ preencher a tela"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ampliar p/ preencher tela"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom em modo de compatibilidade"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5580f01..c7dff3a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Afişaţi"</string>
<string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Permiteţi depanarea USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Permiteţi depanarea USB de pe acest computer?"\n"Amprenta digitală din cheia RSA este"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Permiteţi întotdeauna de pe acest computer"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom pt. a umple ecranul"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Înt. pt. a umple ecranul"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilitate"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 567d1de..d435670 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Просмотр"</string>
<string name="always_use_device" msgid="1450287437017315906">"Использовать по умолчанию для этого USB-устройства"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Использовать по умолчанию для этого USB-аксессуара"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Разрешить отладку по USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Разрешить отладку по USB с этого компьютера?"\n"Контрольная сумма ключа RSA:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Всегда разрешать отладку с этого компьютера"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Подогнать по размерам экрана"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Растянуть на весь экран"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Масштаб и совместимость"</string>
@@ -141,7 +138,7 @@
<string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Передача данных отключена"</string>
<string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнут лимит трафика."\n\n"При восстановлении подключения оператор может взимать плату за передачу данных."</string>
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Восстановить подключение"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет подключения к Интернету"</string>
+ <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 01a8606..b57afe3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Zobraziť"</string>
<string name="always_use_device" msgid="1450287437017315906">"Pre toto zariadenie USB použiť ako predvolené"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Pre toto periférne zar. USB použiť ako predvolené"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Chcete povoliť ladenie USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Chcete povoliť ladenie USB z tohto počítača?"\n"Digitálny odtlačok vášho kľúča RSA je"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Vždy povoliť v tomto počítači"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Priblížiť na celú obrazovku"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Úprava veľkosti z dôvodu kompatibility"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3987d76..5dbbbb4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Прикажи"</string>
<string name="always_use_device" msgid="1450287437017315906">"Користи подразумевано за овај USB уређај"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Користи подразумевано за овај USB додатак"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Желите ли да дозволите отклањање USB грешака?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Желите ли да дозволите отклањање USB грешака са овог рачунара?"\n"Дигитални отисак RSA кључа је"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Увек дозволи овај рачунар"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Зумирај на целом екрану"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Развуци на цео екран"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Компатибилно зумирање"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0c42f87..c24fa36 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"ดู"</string>
<string name="always_use_device" msgid="1450287437017315906">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์ USB นี้"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์เสริม USB นี้"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"อนุญาตการแก้ไขข้อบกพร่องของ USB หรือไม่"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"อนุญาตการแก้ไขข้อบกพร่องของ USB จากคอมพิวเตอร์เครื่องนี้หรือไ่ม่"\n"ลายนิ้วมือคีย์ RSA ของคุณคือ"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"อนุญาตคอมพิวเตอร์เครื่องนี้เสมอ"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ขยายจนเต็มหน้าจอ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ยืดจนเต็มหน้าจอ"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"ความเข้ากันได้ของการย่อ/ขยาย"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index bb0a2bf..ad601c9 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Tingnan"</string>
<string name="always_use_device" msgid="1450287437017315906">"Gamitin bilang default para sa USB device"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Gamitin bilang default sa USB accessory na ito"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Payagan ang Pag-debug ng USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Payagan ang Pag-debug ng USB mula sa computer na ito?"\n"Ang iyong RSA key fingerprint ay"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Palaging payagan ang computer na ito"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"I-zoom upang punan screen"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"I-stretch upang mapuno screen"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom sa pagiging Tugma"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6c30abe..c4c64d9 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Görüntüle"</string>
<string name="always_use_device" msgid="1450287437017315906">"Bu USB cihazı için varsayılan olarak kullan"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar için varsayılan olarak kullan"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"USB Hata Ayıklama işlemine izin verilsin mi?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Bu bilgisayardan USB Hata Ayıklama işlemine izin verilsin mi?"\n"RSA anahtarı parmak iziniz:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Bu bilgisayara her zaman izin ver"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Yakınlaştır (ekranı kaplasın)"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Genişlet (ekran kapansın)"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Uyumluluk yakınlaştırması"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index cef38ecb..c642c87 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Xem"</string>
<string name="always_use_device" msgid="1450287437017315906">"Sử dụng theo mặc định cho thiết bị USB này"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Sử dụng theo mặc định cho phụ kiện USB này"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Cho phép gỡ lỗi USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Cho phép gỡ lỗi USB từ máy tính này?"\n"Tệp tham chiếu chính của RSA của bạn là"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Luôn cho phép máy tính này"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"T.phóng để lấp đầy m.hình"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Giãn ra để lấp đầy m.hình"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Thu phóng tương thích"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d0f4a9c..408f861 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"查看"</string>
<string name="always_use_device" msgid="1450287437017315906">"默认情况下用于该 USB 设备"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"默认情况下用于该 USB 配件"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"是否允许 USB 调试?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"是否允许在此计算机上进行 USB 调试?"\n"您的 RSA 密钥指纹是"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"始终允许在此计算机上进行 USB 调试"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"缩放以填满屏幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"拉伸以填满屏幕"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"兼容性缩放"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2e5211f..debdb1c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"查看"</string>
<string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"允許 USB 偵錯嗎?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"允許透過這台電腦進行 USB 偵錯嗎?"\n"您的 RSA 金鑰指紋如下"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"一律允許這台電腦"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"相容性縮放"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 07c9f0f..f31a11e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -58,12 +58,9 @@
<string name="label_view" msgid="6304565553218192990">"Buka"</string>
<string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Sebenzisa ngokuzenzakalelayo kule-accessory ye-USB"</string>
- <!-- no translation found for usb_debugging_title (1114766024068112429) -->
- <skip />
- <!-- no translation found for usb_debugging_message (719863946976291180) -->
- <skip />
- <!-- no translation found for usb_debugging_always (4253099426793114693) -->
- <skip />
+ <string name="usb_debugging_title" msgid="1114766024068112429">"Vumela ukulungisa iphutha le-USB?"</string>
+ <string name="usb_debugging_message" msgid="719863946976291180">"Vumela isa ukulung-USB Debugging kusuka kule khompyutha?"\n"Izigxivizo zakho zeminwe zokhiye we-RSA ngu-"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="4253099426793114693">"Hlala uvumela le khompyutha"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Sondeza ukugcwalisa isikrini"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Nweba ukugcwalisa isikrini"</string>
<string name="compat_mode_help_header" msgid="7969493989397529910">"Ukuhambelana Kokusondeza"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9539373..94465e2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -28,6 +28,7 @@
<!-- Size of application thumbnail -->
<dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
<dimen name="status_bar_recents_thumbnail_height">145dp</dimen>
+ <dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen>
<!-- Size of application label text -->
<dimen name="status_bar_recents_app_label_text_size">14dip</dimen>
@@ -163,6 +164,9 @@
<integer name="notification_panel_layout_gravity">0x37</integer>
<integer name="settings_panel_layout_gravity">0x37</integer>
+ <!-- Quick settings panels minimum fling open target width. -->
+ <dimen name="settings_panel_fling_gutter">90dp</dimen>
+
<!-- Height of the carrier/wifi name label -->
<dimen name="carrier_label_height">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
new file mode 100644
index 0000000..12e45c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java
@@ -0,0 +1,31 @@
+package com.android.systemui;
+
+import android.service.dreams.Dream;
+
+import com.android.systemui.BeanBag.Board;
+
+public class BeanBagDream extends Dream {
+
+ private Board mBoard;
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ setInteractive(true);
+ mBoard = new Board(this, null);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setContentView(mBoard);
+ lightsOut();
+ mBoard.startAnimation();
+ }
+
+ @Override
+ public void finish() {
+ mBoard.stopAnimation();
+ super.finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
new file mode 100644
index 0000000..f97d4ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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 com.android.systemui;
+
+import android.app.Application;
+
+import com.android.systemui.recent.RecentTasksLoader;
+
+public class SystemUIApplication extends Application {
+ private RecentTasksLoader mRecentTasksLoader;
+
+ public RecentTasksLoader getRecentTasksLoader() {
+ if (mRecentTasksLoader == null) {
+ mRecentTasksLoader = new RecentTasksLoader(this);
+ }
+ return mRecentTasksLoader;
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
deleted file mode 100644
index 18ad682..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.systemui.recent;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.AnimatorSet.Builder;
-import android.animation.ObjectAnimator;
-import android.content.res.Resources;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.Slog;
-import android.view.View;
-
-import com.android.systemui.R;
-
-/* package */ class Choreographer implements Animator.AnimatorListener {
- // should group this into a multi-property animation
- private static final int OPEN_DURATION = 136;
- private static final int CLOSE_DURATION = 230;
- private static final int SCRIM_DURATION = 400;
- private static final String TAG = RecentsPanelView.TAG;
- private static final boolean DEBUG = RecentsPanelView.DEBUG;
-
- boolean mVisible;
- int mPanelHeight;
- RecentsPanelView mRootView;
- View mScrimView;
- View mContentView;
- View mNoRecentAppsView;
- AnimatorSet mContentAnim;
- Animator.AnimatorListener mListener;
-
- // the panel will start to appear this many px from the end
- final int HYPERSPACE_OFFRAMP = 200;
-
- public Choreographer(RecentsPanelView root, View scrim, View content,
- View noRecentApps, Animator.AnimatorListener listener) {
- mRootView = root;
- mScrimView = scrim;
- mContentView = content;
- mListener = listener;
- mNoRecentAppsView = noRecentApps;
- }
-
- void createAnimation(boolean appearing) {
- float start, end;
-
- // 0: on-screen
- // height: off-screen
- float y = mContentView.getTranslationY();
- if (appearing) {
- // we want to go from near-the-top to the top, unless we're half-open in the right
- // general vicinity
- start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
- end = 0;
- } else {
- start = y;
- end = y;
- }
-
- Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
- start, end);
- posAnim.setInterpolator(appearing
- ? new android.view.animation.DecelerateInterpolator(2.5f)
- : new android.view.animation.AccelerateInterpolator(2.5f));
- posAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
-
- Animator fadeAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
- mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
- fadeAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(1.0f)
- : new android.view.animation.AccelerateInterpolator(2.5f));
- fadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
-
- Animator noRecentAppsFadeAnim = null;
- if (mNoRecentAppsView != null && // doesn't exist on large devices
- mNoRecentAppsView.getVisibility() == View.VISIBLE) {
- noRecentAppsFadeAnim = ObjectAnimator.ofFloat(mNoRecentAppsView, "alpha",
- mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
- noRecentAppsFadeAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(1.0f)
- : new android.view.animation.DecelerateInterpolator(1.0f));
- noRecentAppsFadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
- }
-
- mContentAnim = new AnimatorSet();
- final Builder builder = mContentAnim.play(fadeAnim).with(posAnim);
-
- if (noRecentAppsFadeAnim != null) {
- builder.with(noRecentAppsFadeAnim);
- }
-
- if (appearing) {
- Drawable background = mScrimView.getBackground();
- if (background != null) {
- Animator bgAnim = ObjectAnimator.ofInt(background,
- "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
- bgAnim.setDuration(appearing ? SCRIM_DURATION : CLOSE_DURATION);
- builder.with(bgAnim);
- }
- } else {
- final Resources res = mRootView.getResources();
- boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
- if (!isTablet) {
- View recentsTransitionBackground =
- mRootView.findViewById(R.id.recents_transition_background);
- recentsTransitionBackground.setVisibility(View.VISIBLE);
- Drawable bgDrawable = new ColorDrawable(0xFF000000);
- recentsTransitionBackground.setBackground(bgDrawable);
- Animator bgAnim = ObjectAnimator.ofInt(bgDrawable, "alpha", 0, 255);
- bgAnim.setDuration(CLOSE_DURATION);
- bgAnim.setInterpolator(new android.view.animation.AccelerateInterpolator(1f));
- builder.with(bgAnim);
- }
- }
- mContentAnim.addListener(this);
- if (mListener != null) {
- mContentAnim.addListener(mListener);
- }
- }
-
- void startAnimation(boolean appearing) {
- if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
-
- createAnimation(appearing);
-
- // isHardwareAccelerated() checks if we're attached to a window and if that
- // window is HW accelerated-- we were sometimes not attached to a window
- // and buildLayer was throwing an IllegalStateException
- if (mContentView.isHardwareAccelerated()) {
- mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mContentView.buildLayer();
- }
- mContentAnim.start();
-
- mVisible = appearing;
- }
-
- void jumpTo(boolean appearing) {
- mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
- if (mScrimView.getBackground() != null) {
- mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
- }
- View recentsTransitionBackground =
- mRootView.findViewById(R.id.recents_transition_background);
- recentsTransitionBackground.setVisibility(View.INVISIBLE);
- mRootView.requestLayout();
- }
-
- public void setPanelHeight(int h) {
- if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
- mPanelHeight = h;
- }
-
- public void onAnimationCancel(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationCancel");
- // force this to zero so we close the window
- mVisible = false;
- }
-
- public void onAnimationEnd(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationEnd");
- if (!mVisible) {
- mRootView.hideWindow();
- }
- mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
- mContentView.setAlpha(1f);
- mContentAnim = null;
- }
-
- public void onAnimationRepeat(Animator animation) {
- }
-
- public void onAnimationStart(Animator animation) {
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 4d8c168..4281ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -32,6 +32,8 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -42,7 +44,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-public class RecentTasksLoader {
+public class RecentTasksLoader implements View.OnTouchListener {
static final String TAG = "RecentTasksLoader";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -51,17 +53,43 @@
private Context mContext;
private RecentsPanelView mRecentsPanel;
+ private TaskDescription mFirstTask;
+ private boolean mFirstTaskLoaded;
private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
+ private Handler mHandler;
private int mIconDpi;
private Bitmap mDefaultThumbnailBackground;
private Bitmap mDefaultIconBackground;
- private int mNumTasksInFirstScreenful;
+ private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
+
+ private boolean mFirstScreenful;
+ private ArrayList<TaskDescription> mLoadedTasks;
+
+ private enum State { LOADING, LOADED, CANCELLED };
+ private State mState = State.CANCELLED;
+
+ public TaskDescription getFirstTask() {
+ while (!mFirstTaskLoaded) {
+ if (mState == State.CANCELLED) {
+ loadTasksInBackground();
+ }
+ try {
+ if (mState == State.LOADED) {
+ break;
+ }
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ }
+ }
+ return mFirstTask;
+ }
public RecentTasksLoader(Context context) {
mContext = context;
+ mHandler = new Handler();
final Resources res = context.getResources();
@@ -91,16 +119,16 @@
Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
-
- // If we're using the cache, begin listening to the activity manager for
- // updated thumbnails
- final ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
- public void setRecentsPanel(RecentsPanelView recentsPanel) {
- mRecentsPanel = recentsPanel;
- mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
+ public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
+ // Only allow clearing mRecentsPanel if the caller is the current recentsPanel
+ if (newRecentsPanel != null || mRecentsPanel == caller) {
+ mRecentsPanel = newRecentsPanel;
+ if (mRecentsPanel != null) {
+ mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
+ }
+ }
}
public Bitmap getDefaultThumbnail() {
@@ -111,26 +139,33 @@
return mDefaultIconBackground;
}
- // Create an TaskDescription, returning null if the title or icon is null, or if it's the
- // home activity
+ public ArrayList<TaskDescription> getLoadedTasks() {
+ return mLoadedTasks;
+ }
+
+ public boolean isFirstScreenful() {
+ return mFirstScreenful;
+ }
+
+ private boolean isCurrentHomeActivity(ComponentName component, ActivityInfo homeInfo) {
+ if (homeInfo == null) {
+ final PackageManager pm = mContext.getPackageManager();
+ homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
+ .resolveActivityInfo(pm, 0);
+ }
+ return homeInfo != null
+ && homeInfo.packageName.equals(component.getPackageName())
+ && homeInfo.name.equals(component.getClassName());
+ }
+
+ // Create an TaskDescription, returning null if the title or icon is null
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
- ComponentName origActivity, CharSequence description, ActivityInfo homeInfo) {
+ ComponentName origActivity, CharSequence description) {
Intent intent = new Intent(baseIntent);
if (origActivity != null) {
intent.setComponent(origActivity);
}
final PackageManager pm = mContext.getPackageManager();
- if (homeInfo == null) {
- homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
- }
- // Don't load the current home activity.
- if (homeInfo != null
- && homeInfo.packageName.equals(intent.getComponent().getPackageName())
- && homeInfo.name.equals(intent.getComponent().getClassName())) {
- return null;
- }
-
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
@@ -207,7 +242,43 @@
return getFullResDefaultActivityIcon();
}
- public void cancelLoadingThumbnailsAndIcons() {
+ Runnable mPreloadTasksRunnable = new Runnable() {
+ public void run() {
+ loadTasksInBackground();
+ }
+ };
+
+ // additional optimization when we have software system buttons - start loading the recent
+ // tasks on touch down
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ int action = ev.getAction() & MotionEvent.ACTION_MASK;
+ if (action == MotionEvent.ACTION_DOWN) {
+ mHandler.post(mPreloadTasksRunnable);
+ } else if (action == MotionEvent.ACTION_CANCEL) {
+ cancelLoadingThumbnailsAndIcons();
+ mHandler.removeCallbacks(mPreloadTasksRunnable);
+ } else if (action == MotionEvent.ACTION_UP) {
+ // Remove the preloader if we haven't called it yet
+ mHandler.removeCallbacks(mPreloadTasksRunnable);
+ if (!v.isPressed()) {
+ cancelLoadingThumbnailsAndIcons();
+ }
+
+ }
+ return false;
+ }
+
+ public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) {
+ // Only oblige this request if it comes from the current RecentsPanel
+ // (eg when you rotate, the old RecentsPanel request should be ignored)
+ if (mRecentsPanel == caller) {
+ cancelLoadingThumbnailsAndIcons();
+ }
+ }
+
+
+ private void cancelLoadingThumbnailsAndIcons() {
if (mTaskLoader != null) {
mTaskLoader.cancel(false);
mTaskLoader = null;
@@ -216,11 +287,26 @@
mThumbnailLoader.cancel(false);
mThumbnailLoader = null;
}
+ mLoadedTasks = null;
+ mFirstTask = null;
+ mFirstTaskLoaded = false;
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onTaskLoadingCancelled();
+ }
+ mFirstScreenful = false;
+ mState = State.CANCELLED;
}
public void loadTasksInBackground() {
- // cancel all previous loading of tasks and thumbnails
- cancelLoadingThumbnailsAndIcons();
+ loadTasksInBackground(false);
+ }
+ public void loadTasksInBackground(final boolean zeroeth) {
+ if (mState != State.CANCELLED) {
+ return;
+ }
+ mState = State.LOADING;
+ mFirstScreenful = true;
+
final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
new LinkedBlockingQueue<TaskDescription>();
mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
@@ -230,7 +316,14 @@
ArrayList<TaskDescription> newTasks = values[0];
// do a callback to RecentsPanelView to let it know we have more values
// how do we let it know we're all done? just always call back twice
- mRecentsPanel.onTasksLoaded(newTasks);
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful);
+ }
+ if (mLoadedTasks == null) {
+ mLoadedTasks = new ArrayList<TaskDescription>();
+ }
+ mLoadedTasks.addAll(newTasks);
+ mFirstScreenful = false;
}
}
@Override
@@ -254,15 +347,34 @@
ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
// skip the first task - assume it's either the home screen or the current activity.
- final int first = 1;
+ final int first = 0;
for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
if (isCancelled()) {
break;
}
final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+
+ Intent intent = new Intent(recentInfo.baseIntent);
+ if (recentInfo.origActivity != null) {
+ intent.setComponent(recentInfo.origActivity);
+ }
+
+ // Don't load the current home activity.
+ if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
+ if (index == 0) {
+ mFirstTaskLoaded = true;
+ }
+ continue;
+ }
+
+ // Don't load ourselves
+ if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
+ continue;
+ }
+
TaskDescription item = createTaskDescription(recentInfo.id,
recentInfo.persistentId, recentInfo.baseIntent,
- recentInfo.origActivity, recentInfo.description, homeInfo);
+ recentInfo.origActivity, recentInfo.description);
if (item != null) {
while (true) {
@@ -317,7 +429,13 @@
protected void onProgressUpdate(TaskDescription... values) {
if (!isCancelled()) {
TaskDescription td = values[0];
- mRecentsPanel.onTaskThumbnailLoaded(td);
+ if (td.isNull()) { // end sentinel
+ mState = State.LOADED;
+ } else {
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onTaskThumbnailLoaded(td);
+ }
+ }
}
}
@Override
@@ -336,19 +454,25 @@
} catch (InterruptedException e) {
}
}
- if (td.isNull()) {
+ if (td.isNull()) { // end sentinel
+ publishProgress(td);
break;
}
loadThumbnailAndIcon(td);
- synchronized(td) {
- publishProgress(td);
+
+ if (!mFirstTaskLoaded) {
+ mFirstTask = td;
+ mFirstTaskLoaded = true;
}
+ publishProgress(td);
}
Process.setThreadPriority(origPri);
return null;
}
};
+ mFirstTask = null;
+ mFirstTaskLoaded = false;
mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
new file mode 100644
index 0000000..a4c8e64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012 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 com.android.systemui.recent;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+
+public class RecentsActivity extends Activity {
+ public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.TOGGLE_RECENTS";
+ public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.CLOSE_RECENTS";
+
+ private RecentsPanelView mRecentsPanel;
+ private IntentFilter mIntentFilter;
+ private boolean mShowing;
+ private boolean mForeground;
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
+ if (mShowing && !mForeground) {
+ // Captures the case right before we transition to another activity
+ mRecentsPanel.show(false);
+ }
+ }
+ }
+ };
+
+ public class TouchOutsideListener implements View.OnTouchListener {
+ private StatusBarPanel mPanel;
+
+ public TouchOutsideListener(StatusBarPanel panel) {
+ mPanel = panel;
+ }
+
+ public boolean onTouch(View v, MotionEvent ev) {
+ final int action = ev.getAction();
+ if (action == MotionEvent.ACTION_OUTSIDE
+ || (action == MotionEvent.ACTION_DOWN
+ && !mPanel.isInContentArea((int) ev.getX(), (int) ev.getY()))) {
+ dismissAndGoHome();
+ return true;
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mForeground = false;
+ super.onPause();
+ }
+
+ @Override
+ public void onStop() {
+ mShowing = false;
+ if (mRecentsPanel != null) {
+ mRecentsPanel.onUiHidden();
+ }
+ super.onStop();
+ }
+
+ @Override
+ public void onStart() {
+ mShowing = true;
+ super.onStart();
+ }
+
+ @Override
+ public void onResume() {
+ mForeground = true;
+ super.onResume();
+ }
+
+ @Override
+ public void onBackPressed() {
+ dismissAndGoBack();
+ }
+
+ public void dismissAndGoHome() {
+ if (mRecentsPanel != null) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startActivityAsUser(homeIntent, new UserHandle(UserHandle.USER_CURRENT));
+ mRecentsPanel.show(false);
+ }
+ }
+
+ public void dismissAndGoBack() {
+ if (mRecentsPanel != null) {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ TaskDescription firstTask = recentTasksLoader.getFirstTask();
+ if (firstTask != null && mRecentsPanel.simulateClick(firstTask)) {
+ // recents panel will take care of calling show(false);
+ return;
+ }
+ mRecentsPanel.show(false);
+ }
+ finish();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+
+ setContentView(R.layout.status_bar_recent_panel);
+ mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
+ mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
+ mRecentsPanel.setRecentTasksLoader(recentTasksLoader);
+ recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
+
+ handleIntent(getIntent());
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
+ registerReceiver(mIntentReceiver, mIntentFilter);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ recentTasksLoader.setRecentsPanel(null, mRecentsPanel);
+ unregisterReceiver(mIntentReceiver);
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ handleIntent(intent);
+ }
+
+ private void handleIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
+ if (mRecentsPanel != null && !mRecentsPanel.isShowing()) {
+ final SystemUIApplication app = (SystemUIApplication) getApplication();
+ final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+ mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
+ recentTasksLoader.isFirstScreenful());
+ } else if ((mRecentsPanel != null && mRecentsPanel.isShowing())) {
+ dismissAndGoBack();
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index e9c2ecb7..4aa2095 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -76,6 +76,17 @@
}
}
+ public View findViewForTask(TaskDescription task) {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
+ if (holder.taskDescription == task) {
+ return v;
+ }
+ }
+ return null;
+ }
+
private void update() {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index b407078..c3ecdb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -29,20 +29,17 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Matrix;
-import android.graphics.Rect;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
-import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -71,7 +68,7 @@
import java.util.ArrayList;
public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
- StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
+ StatusBarPanel, Animator.AnimatorListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
private Context mContext;
@@ -84,36 +81,22 @@
private boolean mShowing;
private boolean mWaitingToShow;
- private boolean mWaitingToShowAnimated;
- private boolean mReadyToShow;
private int mNumItemsWaitingForThumbnailsAndIcons;
- private Choreographer mChoreo;
- OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
-
- ImageView mPlaceholderThumbnail;
- View mTransitionBg;
- boolean mHideRecentsAfterThumbnailScaleUpStarted;
private RecentTasksLoader mRecentTasksLoader;
private ArrayList<TaskDescription> mRecentTaskDescriptions;
- private Runnable mPreloadTasksRunnable;
- private boolean mRecentTasksDirty = true;
private TaskDescriptionAdapter mListAdapter;
private int mThumbnailWidth;
private boolean mFitThumbnailToXY;
private int mRecentItemLayoutId;
- private boolean mFirstScreenful = true;
private boolean mHighEndGfx;
- public static interface OnRecentsPanelVisibilityChangedListener {
- public void onRecentsPanelVisibilityChanged(boolean visible);
- }
-
public static interface RecentsScrollView {
public int numItemsInOneScreenful();
public void setAdapter(TaskDescriptionAdapter adapter);
public void setCallback(RecentsCallback callback);
public void setMinSwipeAlpha(float minAlpha);
+ public View findViewForTask(TaskDescription task);
}
private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -252,15 +235,6 @@
}
}
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && !event.isCanceled()) {
- show(false, false);
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-
private boolean pointInside(int x, int y, View v) {
final int l = v.getLeft();
final int r = v.getRight();
@@ -280,22 +254,26 @@
}
}
- public void show(boolean show, boolean animate) {
+ public void show(boolean show) {
+ show(show, null, false);
+ }
+
+ public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
+ boolean firstScreenful) {
if (show) {
- refreshRecentTasksList(null, true);
mWaitingToShow = true;
- mWaitingToShowAnimated = animate;
+ refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
showIfReady();
} else {
- show(show, animate, null, false);
+ showImpl(false);
}
}
private void showIfReady() {
- // mWaitingToShow = there was a touch up on the recents button
- // mReadyToShow = we've created views for the first screenful of items
- if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0
- show(true, mWaitingToShowAnimated, null, false);
+ // mWaitingToShow => there was a touch up on the recents button
+ // mRecentTaskDescriptions != null => we've created views for the first screenful of items
+ if (mWaitingToShow && mRecentTaskDescriptions != null) {
+ showImpl(true);
}
}
@@ -308,79 +286,44 @@
}
}
- public void show(boolean show, boolean animate,
- ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
+ private void showImpl(boolean show) {
sendCloseSystemWindows(mContext, BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
+ mShowing = show;
+
if (show) {
- // Need to update list of recent apps before we set visibility so this view's
- // content description is updated before it gets focus for TalkBack mode
- refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
+ // if there are no apps, bring up a "No recent apps" message
+ boolean noApps = mRecentTaskDescriptions != null
+ && (mRecentTaskDescriptions.size() == 0);
+ mRecentsNoApps.setAlpha(1f);
+ mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
- // if there are no apps, either bring up a "No recent apps" message, or just
- // quit early
- boolean noApps = !mFirstScreenful && (mRecentTaskDescriptions.size() == 0);
- if (mRecentsNoApps != null) {
- mRecentsNoApps.setAlpha(1f);
- mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
- } else {
- if (noApps) {
- if (DEBUG) Log.v(TAG, "Nothing to show");
- // Need to set recent tasks to dirty so that next time we load, we
- // refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
- mRecentTasksDirty = true;
-
- mWaitingToShow = false;
- mReadyToShow = false;
- return;
- }
- }
- } else {
- // Need to set recent tasks to dirty so that next time we load, we
- // refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
- mRecentTasksDirty = true;
- mWaitingToShow = false;
- mReadyToShow = false;
- }
- if (animate) {
- if (mShowing != show) {
- mShowing = show;
- if (show) {
- setVisibility(View.VISIBLE);
- }
- mChoreo.startAnimation(show);
- }
- } else {
- mShowing = show;
- setVisibility(show ? View.VISIBLE : View.GONE);
- mChoreo.jumpTo(show);
onAnimationEnd(null);
- }
- if (show) {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
} else {
+ mWaitingToShow = false;
+ // call onAnimationEnd() and clearRecentTasksList() in onUiHidden()
if (mPopup != null) {
mPopup.dismiss();
}
}
}
- public void dismiss() {
- hide(true);
+ public void onUiHidden() {
+ if (!mShowing && mRecentTaskDescriptions != null) {
+ onAnimationEnd(null);
+ clearRecentTasksList();
+ }
}
- public void hide(boolean animate) {
- if (!animate) {
- setVisibility(View.GONE);
- }
- if (mBar != null) {
- // This will indirectly cause show(false, ...) to get called
- mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
- }
+ public void dismiss() {
+ ((RecentsActivity) mContext).dismissAndGoHome();
+ }
+
+ public void dismissAndGoBack() {
+ ((RecentsActivity) mContext).dismissAndGoBack();
}
public void onAnimationCancel(Animator animation) {
@@ -393,7 +336,6 @@
createCustomAnimations(transitioner);
} else {
((ViewGroup)mRecentsContainer).setLayoutTransition(null);
- clearRecentTasksList();
}
}
@@ -403,16 +345,6 @@
public void onAnimationStart(Animator animation) {
}
- /**
- * We need to be aligned at the bottom. LinearLayout can't do this, so instead,
- * let LinearLayout do all the hard work, and then shift everything down to the bottom.
- */
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mChoreo.setPanelHeight(mRecentsContainer.getHeight());
- }
-
@Override
public boolean dispatchHoverEvent(MotionEvent event) {
// Ignore hover events outside of this panel bounds since such events
@@ -449,18 +381,6 @@
mRecentTasksLoader = loader;
}
- public void setOnVisibilityChangedListener(OnRecentsPanelVisibilityChangedListener l) {
- mVisibilityChangedListener = l;
-
- }
-
- public void setVisibility(int visibility) {
- if (mVisibilityChangedListener != null) {
- mVisibilityChangedListener.onRecentsPanelVisibilityChanged(visibility == VISIBLE);
- }
- super.setVisibility(visibility);
- }
-
public void updateValuesFromResources() {
final Resources res = mContext.getResources();
mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
@@ -486,7 +406,6 @@
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
- mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
if (mRecentsScrim != null) {
mHighEndGfx = ActivityManager.isHighEndGfx();
@@ -497,18 +416,6 @@
((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
}
}
-
- mPreloadTasksRunnable = new Runnable() {
- public void run() {
- // If we set our visibility to INVISIBLE here, we avoid an extra call to
- // onLayout later when we become visible (because onLayout is always called
- // when going from GONE)
- if (!mShowing) {
- setVisibility(INVISIBLE);
- refreshRecentTasksList();
- }
- }
- };
}
public void setMinSwipeAlpha(float minAlpha) {
@@ -602,44 +509,19 @@
showIfReady();
}
- // additional optimization when we have software system buttons - start loading the recent
- // tasks on touch down
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- if (!mShowing) {
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
- if (action == MotionEvent.ACTION_DOWN) {
- post(mPreloadTasksRunnable);
- } else if (action == MotionEvent.ACTION_CANCEL) {
- setVisibility(GONE);
- clearRecentTasksList();
- // Remove the preloader if we haven't called it yet
- removeCallbacks(mPreloadTasksRunnable);
- } else if (action == MotionEvent.ACTION_UP) {
- // Remove the preloader if we haven't called it yet
- removeCallbacks(mPreloadTasksRunnable);
- if (!v.isPressed()) {
- setVisibility(GONE);
- clearRecentTasksList();
- }
- }
- }
- return false;
- }
-
- public void preloadRecentTasksList() {
- if (!mShowing) {
- mPreloadTasksRunnable.run();
- }
- }
-
public void clearRecentTasksList() {
// Clear memory used by screenshots
- if (!mShowing && mRecentTaskDescriptions != null) {
- mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
- mRecentTaskDescriptions.clear();
+ if (mRecentTaskDescriptions != null) {
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(this);
+ onTaskLoadingCancelled();
+ }
+ }
+
+ public void onTaskLoadingCancelled() {
+ // Gets called by RecentTasksLoader when it's cancelled
+ if (mRecentTaskDescriptions != null) {
+ mRecentTaskDescriptions = null;
mListAdapter.notifyDataSetInvalidated();
- mRecentTasksDirty = true;
}
}
@@ -649,23 +531,15 @@
private void refreshRecentTasksList(
ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
- if (mRecentTasksDirty) {
- if (recentTasksList != null) {
- mFirstScreenful = true;
- onTasksLoaded(recentTasksList);
- } else {
- mFirstScreenful = true;
- mRecentTasksLoader.loadTasksInBackground();
- }
- mRecentTasksDirty = false;
+ if (mRecentTaskDescriptions == null && recentTasksList != null) {
+ onTasksLoaded(recentTasksList, firstScreenful);
+ } else {
+ mRecentTasksLoader.loadTasksInBackground();
}
}
- public void onTasksLoaded(ArrayList<TaskDescription> tasks) {
- if (!mFirstScreenful && tasks.size() == 0) {
- return;
- }
- mNumItemsWaitingForThumbnailsAndIcons = mFirstScreenful
+ public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
+ mNumItemsWaitingForThumbnailsAndIcons = firstScreenful
? tasks.size() : mRecentTaskDescriptions == null
? 0 : mRecentTaskDescriptions.size();
if (mRecentTaskDescriptions == null) {
@@ -675,19 +549,9 @@
}
mListAdapter.notifyDataSetInvalidated();
updateUiElements(getResources().getConfiguration());
- mReadyToShow = true;
- mFirstScreenful = false;
showIfReady();
}
- public ArrayList<TaskDescription> getRecentTasksList() {
- return mRecentTaskDescriptions;
- }
-
- public boolean getFirstScreenful() {
- return mFirstScreenful;
- }
-
private void updateUiElements(Configuration config) {
final int items = mRecentTaskDescriptions.size();
@@ -706,8 +570,19 @@
setContentDescription(recentAppsAccessibilityDescription);
}
+ public boolean simulateClick(TaskDescription task) {
+ if (mRecentsContainer instanceof RecentsScrollView){
+ RecentsScrollView scrollView
+ = (RecentsScrollView) mRecentsContainer;
+ View v = scrollView.findViewForTask(task);
+ if (v != null) {
+ handleOnClick(v);
+ return true;
+ }
+ }
+ return false;
+ }
- boolean mThumbnailScaleUpStarted;
public void handleOnClick(View view) {
ViewHolder holder = (ViewHolder)view.getTag();
TaskDescription ad = holder.taskDescription;
@@ -725,59 +600,10 @@
usingDrawingCache = true;
}
- if (mPlaceholderThumbnail == null) {
- mPlaceholderThumbnail =
- (ImageView) findViewById(R.id.recents_transition_placeholder_icon);
- }
- if (mTransitionBg == null) {
- mTransitionBg = (View) findViewById(R.id.recents_transition_background);
-
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- try {
- if (!wm.hasSystemNavBar()) {
- FrameLayout.LayoutParams lp =
- (FrameLayout.LayoutParams) mTransitionBg.getLayoutParams();
- int statusBarHeight = getResources().
- getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- lp.setMargins(0, statusBarHeight, 0, 0);
- mTransitionBg.setLayoutParams(lp);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failing checking whether status bar is visible", e);
- }
- }
-
- final ImageView placeholderThumbnail = mPlaceholderThumbnail;
- mHideRecentsAfterThumbnailScaleUpStarted = false;
- placeholderThumbnail.setVisibility(VISIBLE);
- if (!usingDrawingCache) {
- placeholderThumbnail.setImageBitmap(bm);
- } else {
- Bitmap b2 = bm.copy(bm.getConfig(), true);
- placeholderThumbnail.setImageBitmap(b2);
- }
- Rect r = new Rect();
- holder.thumbnailViewImage.getGlobalVisibleRect(r);
-
- placeholderThumbnail.setTranslationX(r.left);
- placeholderThumbnail.setTranslationY(r.top);
-
- show(false, true);
-
- mThumbnailScaleUpStarted = false;
ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
- holder.thumbnailViewImage, bm, 0, 0,
- new ActivityOptions.OnAnimationStartedListener() {
- @Override public void onAnimationStarted() {
- mThumbnailScaleUpStarted = true;
- if (!mHighEndGfx) {
- mPlaceholderThumbnail.setVisibility(INVISIBLE);
- }
- if (mHideRecentsAfterThumbnailScaleUpStarted) {
- hideWindow();
- }
- }
- });
+ holder.thumbnailViewImage, bm, 0, 0, null);
+
+ show(false);
if (ad.taskId >= 0) {
// This is an active task; it should just go to the foreground.
am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
@@ -796,17 +622,6 @@
}
}
- public void hideWindow() {
- if (!mThumbnailScaleUpStarted) {
- mHideRecentsAfterThumbnailScaleUpStarted = true;
- } else {
- setVisibility(GONE);
- mTransitionBg.setVisibility(INVISIBLE);
- mPlaceholderThumbnail.setVisibility(INVISIBLE);
- mHideRecentsAfterThumbnailScaleUpStarted = false;
- }
- }
-
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
handleOnClick(view);
}
@@ -825,7 +640,7 @@
// mListAdapter.notifyDataSetChanged();
if (mRecentTaskDescriptions.size() == 0) {
- hide(false);
+ dismissAndGoBack();
}
// Currently, either direction means the same thing, so ignore direction and remove
@@ -875,7 +690,7 @@
if (viewHolder != null) {
final TaskDescription ad = viewHolder.taskDescription;
startApplicationDetailsActivity(ad.packageName);
- mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
+ show(false);
} else {
throw new IllegalStateException("Oops, no tag on view " + selectedView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index ba08775..a0f197dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -77,6 +77,17 @@
}
}
+ public View findViewForTask(TaskDescription task) {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
+ if (holder.taskDescription == task) {
+ return v;
+ }
+ }
+ return null;
+ }
+
private void update() {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
@@ -146,7 +157,9 @@
appTitle.setContentDescription(" ");
appTitle.setOnTouchListener(noOpListener);
final View calloutLine = view.findViewById(R.id.recents_callout_line);
- calloutLine.setOnTouchListener(noOpListener);
+ if (calloutLine != null) {
+ calloutLine.setOnTouchListener(noOpListener);
+ }
mLinearLayout.addView(view);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index e9e043e..106ce7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2010 The Android Open Source Project
*
@@ -24,23 +25,31 @@
import com.android.systemui.R;
import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIApplication;
import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsPanelView;
+import com.android.systemui.recent.RecentsActivity;
import com.android.systemui.recent.TaskDescription;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.PendingIntent;
+import android.app.Service;
import android.app.TaskStackBuilder;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -52,6 +61,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
import android.view.Display;
@@ -73,12 +83,12 @@
import java.util.ArrayList;
public abstract class BaseStatusBar extends SystemUI implements
- CommandQueue.Callbacks, RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
+ CommandQueue.Callbacks {
static final String TAG = "StatusBar";
private static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
- protected static final int MSG_OPEN_RECENTS_PANEL = 1020;
+ protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
@@ -111,10 +121,6 @@
// Search panel
protected SearchPanelView mSearchPanelView;
- // Recent apps
- protected RecentsPanelView mRecentsPanel;
- protected RecentTasksLoader mRecentTasksLoader;
-
protected PopupMenu mNotificationBlamePopup;
protected int mCurrentUserId = 0;
@@ -377,8 +383,7 @@
@Override
public void toggleRecentApps() {
- int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
- ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
+ int msg = MSG_TOGGLE_RECENTS_PANEL;
mHandler.removeMessages(msg);
mHandler.sendEmptyMessage(msg);
}
@@ -411,49 +416,15 @@
mHandler.sendEmptyMessage(msg);
}
- @Override
- public void onRecentsPanelVisibilityChanged(boolean visible) {
- }
-
protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
LayoutParams layoutParams);
protected abstract WindowManager.LayoutParams getSearchLayoutParams(
LayoutParams layoutParams);
- protected void updateRecentsPanel(int recentsResId) {
- // Recents Panel
- boolean visible = false;
- ArrayList<TaskDescription> recentTasksList = null;
- boolean firstScreenful = false;
- if (mRecentsPanel != null) {
- visible = mRecentsPanel.isShowing();
- mWindowManager.removeView(mRecentsPanel);
- if (visible) {
- recentTasksList = mRecentsPanel.getRecentTasksList();
- firstScreenful = mRecentsPanel.getFirstScreenful();
- }
- }
-
- // Provide RecentsPanelView with a temporary parent to allow layout params to work.
- LinearLayout tmpRoot = new LinearLayout(mContext);
- mRecentsPanel = (RecentsPanelView) LayoutInflater.from(mContext).inflate(
- recentsResId, tmpRoot, false);
- mRecentsPanel.setRecentTasksLoader(mRecentTasksLoader);
- mRecentTasksLoader.setRecentsPanel(mRecentsPanel);
- mRecentsPanel.setOnTouchListener(
- new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL, mRecentsPanel));
- mRecentsPanel.setVisibility(View.GONE);
-
-
- WindowManager.LayoutParams lp = getRecentsLayoutParams(mRecentsPanel.getLayoutParams());
-
- mWindowManager.addView(mRecentsPanel, lp);
- mRecentsPanel.setBar(this);
- if (visible) {
- mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
- }
-
+ protected RecentTasksLoader getRecentTasksLoader() {
+ final SystemUIApplication app = (SystemUIApplication) ((Service) mContext).getApplication();
+ return app.getRecentTasksLoader();
}
protected void updateSearchPanel() {
@@ -494,28 +465,148 @@
}
}
+ protected abstract View getStatusBarView();
+
+ protected void toggleRecentsActivity() {
+ try {
+ final RecentTasksLoader recentTasksLoader = getRecentTasksLoader();
+ TaskDescription firstTask = recentTasksLoader.getFirstTask();
+
+ Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.recent.RecentsActivity");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+ if (firstTask == null) {
+ mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ } else {
+ Bitmap first = firstTask.getThumbnail();
+ final Resources res = mContext.getResources();
+
+ float thumbWidth = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
+ float thumbHeight = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
+ if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
+ first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
+ true);
+ }
+
+ DisplayMetrics dm = new DisplayMetrics();
+ mDisplay.getMetrics(dm);
+ // calculate it here, but consider moving it elsewhere
+ // first, determine which orientation you're in.
+ // todo: move the system_bar layouts to sw600dp ?
+ final Configuration config = res.getConfiguration();
+ int x, y;
+
+ if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ float appLabelLeftMargin = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_left_margin);
+ float appLabelWidth = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_width);
+ float thumbLeftMargin = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_left_margin);
+ float thumbBgPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_bg_padding);
+
+ float width = appLabelLeftMargin +
+ +appLabelWidth
+ + thumbLeftMargin
+ + thumbWidth
+ + 2 * thumbBgPadding;
+
+ x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
+ + thumbBgPadding + thumbLeftMargin);
+ y = (int) (dm.heightPixels
+ - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height) - thumbBgPadding);
+ } else { // if (config.orientation ==
+ // Configuration.ORIENTATION_LANDSCAPE) {
+ float thumbTopMargin = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_top_margin);
+ float thumbBgPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_bg_padding);
+ float textPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_text_description_padding);
+ float labelTextSize = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_label_text_size);
+ Paint p = new Paint();
+ p.setTextSize(labelTextSize);
+ float labelTextHeight = p.getFontMetricsInt().bottom
+ - p.getFontMetricsInt().top;
+ float descriptionTextSize = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_app_description_text_size);
+ p.setTextSize(labelTextSize);
+ float descriptionTextHeight = p.getFontMetricsInt().bottom
+ - p.getFontMetricsInt().top;
+
+ float statusBarHeight = res
+ .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ float recentsItemTopPadding = statusBarHeight;
+
+ float height = thumbTopMargin
+ + thumbHeight
+ + 2 * thumbBgPadding + textPadding + labelTextHeight
+ + recentsItemTopPadding + textPadding + descriptionTextHeight;
+ float recentsItemRightPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
+ float recentsScrollViewRightPadding = res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
+ x = (int) (dm.widthPixels - res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
+ - thumbBgPadding - recentsItemRightPadding - recentsScrollViewRightPadding);
+ y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
+ + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
+ }
+
+ ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
+ getStatusBarView(),
+ first, x, y,
+ null);
+ mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
+ UserHandle.USER_CURRENT));
+ }
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Failed to launch RecentAppsIntent", e);
+ }
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
- case MSG_OPEN_RECENTS_PANEL:
- if (DEBUG) Slog.d(TAG, "opening recents panel");
- if (mRecentsPanel != null) {
- mRecentsPanel.show(true, false);
- }
- break;
+ case MSG_TOGGLE_RECENTS_PANEL:
+ if (DEBUG) Slog.d(TAG, "toggle recents panel");
+ toggleRecentsActivity();
+ break;
case MSG_CLOSE_RECENTS_PANEL:
- if (DEBUG) Slog.d(TAG, "closing recents panel");
- if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
- mRecentsPanel.show(false, false);
- }
- break;
+ if (DEBUG) Slog.d(TAG, "closing recents panel");
+ Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+ intent.setPackage("com.android.systemui");
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ break;
case MSG_PRELOAD_RECENT_APPS:
if (DEBUG) Slog.d(TAG, "preloading recents");
- mRecentsPanel.preloadRecentTasksList();
+ {
+ // TODO:
+ // need to implement this
+ //final RecentsPanelView recentsPanel = getRecentsPanel();
+ //if (recentsPanel != null) {
+ //recentsPanel.preloadRecentTasksList();
+ //}
+ }
break;
case MSG_CANCEL_PRELOAD_RECENT_APPS:
if (DEBUG) Slog.d(TAG, "cancel preloading recents");
- mRecentsPanel.clearRecentTasksList();
+ {
+ // TODO:
+ // need to implement this
+ //final RecentsPanelView recentsPanel = getRecentsPanel();
+ //if (recentsPanel != null) {
+ //recentsPanel.clearRecentTasksList();
+ //}
+ }
break;
case MSG_OPEN_SEARCH_PANEL:
if (DEBUG) Slog.d(TAG, "opening search panel");
@@ -559,8 +650,6 @@
}
protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
- int rowHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
int minHeight =
mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight =
@@ -605,7 +694,6 @@
// TODO(cwren) normalize variable names with those in updateNotification
View expandedOneU = null;
View expandedLarge = null;
- Exception exception = null;
try {
expandedOneU = oneU.apply(mContext, adaptive, mOnClickHandler);
if (large != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 13a34ad..9c978d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -17,11 +17,23 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import com.android.systemui.R;
public class NotificationPanelView extends PanelView {
+
+ Drawable mHandleBar;
+ float mHandleBarHeight;
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ Resources resources = context.getResources();
+ mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
+ mHandleBarHeight = resources.getDimension(R.dimen.close_handle_height);
}
@Override
@@ -31,4 +43,20 @@
"notifications,v=" + vel);
super.fling(vel, always);
}
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed) {
+ mHandleBar.setBounds(0, 0, getWidth(), (int) mHandleBarHeight);
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ canvas.translate(0, getHeight() - mHandleBarHeight);
+ mHandleBar.draw(canvas);
+ canvas.translate(0, -getHeight() + mHandleBarHeight);
+ }
}
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 2886441..9d2678a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -445,9 +445,6 @@
// if (wimaxRSSI != null) {
// mNetworkController.addWimaxIconView(wimaxRSSI);
// }
- // Recents Panel
- mRecentTasksLoader = new RecentTasksLoader(context);
- updateRecentsPanel();
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -460,6 +457,11 @@
}
@Override
+ protected View getStatusBarView() {
+ return mStatusBarView;
+ }
+
+ @Override
protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
boolean opaque = false;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -507,6 +509,7 @@
return lp;
}
+ /*
protected void updateRecentsPanel() {
super.updateRecentsPanel(R.layout.status_bar_recent_panel);
// Make .03 alpha the minimum so you always see the item a bit-- slightly below
@@ -517,6 +520,7 @@
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
}
}
+ */
@Override
protected void updateSearchPanel() {
@@ -604,7 +608,7 @@
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
- mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
+ mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader());
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
updateSearchPanel();
}
@@ -785,7 +789,6 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- updateRecentsPanel();
updateShowSearchHoldoff();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 6d47493..8fe525c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -43,6 +43,9 @@
private static final String TAG = "PhoneStatusBarView";
PhoneStatusBar mBar;
int mScrimColor;
+ float mMinFlingGutter;
+ float mNotificationWidth;
+ boolean mFullWidthNotifications;
PanelView mFadingPanel = null;
PanelView mNotificationPanel, mSettingsPanel;
@@ -58,6 +61,13 @@
public void onAttachedToWindow() {
Resources res = getContext().getResources();
mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
+ mMinFlingGutter = res.getDimension(R.dimen.settings_panel_fling_gutter);
+ mFullWidthNotifications = false;
+ try {
+ mNotificationWidth = res.getDimension(R.dimen.notification_panel_width);
+ } catch (Resources.NotFoundException ex) {
+ mFullWidthNotifications = true;
+ }
}
@Override
@@ -96,9 +106,12 @@
// right 1/3 for quick settings. If you pull the status bar down a second time you'll
// toggle panels no matter where you pull it down.
final float w = (float) getMeasuredWidth();
+ final float gutter = w - mNotificationWidth;
+ final boolean useGutter = !mFullWidthNotifications && gutter > mMinFlingGutter;
+ final float threshold = 1.0f - (gutter / w);
final float f = x / w;
- if (f > 0.67f && mSettingsPanel.getExpandedFraction() != 1.0f
- || mNotificationPanel.getExpandedFraction() == 1.0f) {
+ if ((useGutter && f > threshold && mSettingsPanel.getExpandedFraction() != 1.0f) ||
+ mNotificationPanel.getExpandedFraction() == 1.0f) {
return mSettingsPanel;
}
return mNotificationPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 84697e0..8ca3a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -84,8 +84,7 @@
import java.util.ArrayList;
public class TabletStatusBar extends BaseStatusBar implements
- InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
- RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
+ InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
public static final boolean DEBUG = false;
public static final boolean DEBUG_COMPAT_HELP = false;
public static final String TAG = "TabletStatusBar";
@@ -305,10 +304,6 @@
mWindowManager.addView(mNotificationPanel, lp);
- // Recents Panel
- mRecentTasksLoader = new RecentTasksLoader(context);
- updateRecentsPanel();
-
// Search Panel
mStatusBarView.setBar(this);
mHomeButton.setOnTouchListener(mHomeSearchActionListener);
@@ -360,7 +355,7 @@
mWindowManager.addView(mCompatModePanel, lp);
- mRecentButton.setOnTouchListener(mRecentsPanel);
+ //mRecentButton.setOnTouchListener(mRecentsPanel); //TODO: plumb this
mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
mPile.removeAllViews();
@@ -393,7 +388,6 @@
loadDimens();
mNotificationPanelParams.height = getNotificationPanelHeight();
mWindowManager.updateViewLayout(mNotificationPanel, mNotificationPanelParams);
- mRecentsPanel.updateValuesFromResources();
mShowSearchHoldoff = mContext.getResources().getInteger(
R.integer.config_show_search_delay);
updateSearchPanel();
@@ -445,6 +439,7 @@
}
}
+ @Override
public View getStatusBarView() {
return mStatusBarView;
}
@@ -656,11 +651,6 @@
return lp;
}
- protected void updateRecentsPanel() {
- super.updateRecentsPanel(R.layout.system_bar_recent_panel);
- mRecentsPanel.setStatusBarView(mStatusBarView);
- }
-
@Override
protected void updateSearchPanel() {
super.updateSearchPanel();
@@ -1183,14 +1173,6 @@
}
@Override
- public void onRecentsPanelVisibilityChanged(boolean visible) {
- boolean altBack = visible || mAltBackButtonEnabledForIme;
- mCommandQueue.setNavigationIconHints(
- altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
- : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
- }
-
- @Override
public void setHardKeyboardStatus(boolean available, boolean enabled) {
if (DEBUG) {
Slog.d(TAG, "Set hard keyboard status: available=" + available
@@ -1241,10 +1223,7 @@
public void onClickRecentButton() {
if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
- int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
- ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
+ toggleRecentApps();
}
}
@@ -1523,14 +1502,6 @@
flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
- if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- // If we're turning the screen off, we want to hide the
- // recents panel with no animation
- // TODO: hide other things, like the notification tray,
- // with no animation as well
- mRecentsPanel.show(false, false);
- flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
- }
animateCollapse(flags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 5a598dc..6022fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -148,6 +148,10 @@
return mView;
}
+ public View getStatusBarView() {
+ return null;
+ }
+
protected int getStatusBarGravity() {
return 0;
}
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 9999adb1..96de1b9 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -79,7 +79,7 @@
mDataReceived = (TextView) view.findViewById(R.id.data_received);
mDataRowsHidden = true;
- if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
+ if (mConfig.legacy) {
mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
mAlertParams.mTitle = getText(R.string.legacy_title);
} else {
@@ -123,7 +123,11 @@
if (which == DialogInterface.BUTTON_POSITIVE) {
mConfig.configureIntent.send();
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
- mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+ if (mConfig.legacy) {
+ mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+ } else {
+ mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
+ }
}
} catch (Exception e) {
Log.e(TAG, "onClick", e);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 4d05a87..236a4ea 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -39,6 +39,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.EventLog;
@@ -970,7 +971,7 @@
* interacts with the keyguard ui should be posted to this handler, rather
* than called directly.
*/
- private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
+ private Handler mHandler = new Handler(true /*async*/) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -1030,7 +1031,9 @@
mPM.wakeUp(SystemClock.uptimeMillis());
}
mWakeLock.release();
- mContext.sendBroadcast(mUserPresentIntent);
+
+ final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
+ mContext.sendBroadcastAsUser(mUserPresentIntent, currentUser);
}
/**
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
index 17f99b9..21e706f 100644
--- a/services/common_time/common_time_server.cpp
+++ b/services/common_time/common_time_server.cpp
@@ -53,9 +53,9 @@
namespace android {
-const char* CommonTimeServer::kDefaultMasterElectionAddr = "239.195.128.88";
-const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8887;
-const uint64_t CommonTimeServer::kDefaultSyncGroupID = 0;
+const char* CommonTimeServer::kDefaultMasterElectionAddr = "255.255.255.255";
+const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8886;
+const uint64_t CommonTimeServer::kDefaultSyncGroupID = 1;
const uint8_t CommonTimeServer::kDefaultMasterPriority = 1;
const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000;
const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000;
@@ -752,6 +752,9 @@
bool CommonTimeServer::handleWhoIsMasterRequest(
const WhoIsMasterRequestPacket* request,
const sockaddr_storage& srcAddr) {
+ // Skip our own messages which come back via broadcast loopback.
+ if (request->senderDeviceID == mDeviceID)
+ return true;
char srcEPStr[64];
sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
@@ -829,6 +832,10 @@
bool CommonTimeServer::handleWhoIsMasterResponse(
const WhoIsMasterResponsePacket* response,
const sockaddr_storage& srcAddr) {
+ // Skip our own messages which come back via broadcast loopback.
+ if (response->deviceID == mDeviceID)
+ return true;
+
char srcEPStr[64];
sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
mElectionLog.log("RXed WhoIs master response while in state %s. "
@@ -996,6 +1003,10 @@
uint8_t newDevicePrio = packet->devicePriority;
uint64_t newTimelineID = packet->timelineID;
+ // Skip our own messages which come back via broadcast loopback.
+ if (newDeviceID == mDeviceID)
+ return true;
+
char srcEPStr[64];
sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
mElectionLog.log("RXed master announcement while in state %s. "
diff --git a/services/java/Android.mk b/services/java/Android.mk
index e70a6c9..95b28d9 100644
--- a/services/java/Android.mk
+++ b/services/java/Android.mk
@@ -13,9 +13,6 @@
LOCAL_JAVA_LIBRARIES := android.policy telephony-common
-LOCAL_NO_EMMA_INSTRUMENT := true
-LOCAL_NO_EMMA_COMPILE := true
-
include $(BUILD_JAVA_LIBRARY)
include $(BUILD_DROIDDOC)
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 6ae16a4..4192a93 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -204,6 +204,11 @@
return mBatteryLevel;
}
+ // true if battery level is below the first warning threshold
+ public final boolean isBatteryLow() {
+ return mBatteryPresent && mBatteryLevel <= mLowBatteryWarningLevel;
+ }
+
void systemReady() {
// check our power situation now that it is safe to display the shutdown dialog.
shutdownIfNoPower();
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cb6ce4b..3c2ab16 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -31,6 +31,8 @@
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
import android.content.Context;
@@ -78,6 +80,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.security.KeyStore;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
@@ -85,8 +88,10 @@
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.util.Preconditions;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
@@ -115,13 +120,15 @@
* @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
+ private static final String TAG = "ConnectivityService";
private static final boolean DBG = true;
private static final boolean VDBG = false;
- private static final String TAG = "ConnectivityService";
private static final boolean LOGD_RULES = false;
+ // TODO: create better separation between radio types and network types
+
// how long to wait before switching back to a radio's default network
private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
// system property that can override the above value
@@ -135,7 +142,10 @@
private Tethering mTethering;
private boolean mTetheringConfigValid = false;
+ private final KeyStore mKeyStore;
+
private Vpn mVpn;
+ private VpnCallback mVpnCallback = new VpnCallback();
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
private Object mRulesLock = new Object();
@@ -328,7 +338,7 @@
this(context, netd, statsService, policyManager, null);
}
- public ConnectivityService(Context context, INetworkManagementService netd,
+ public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
NetworkFactory netFactory) {
if (DBG) log("ConnectivityService starting up");
@@ -366,8 +376,9 @@
}
mContext = checkNotNull(context, "missing Context");
- mNetd = checkNotNull(netd, "missing INetworkManagementService");
+ mNetd = checkNotNull(netManager, "missing INetworkManagementService");
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
+ mKeyStore = KeyStore.getInstance();
try {
mPolicyManager.registerListener(mPolicyListener);
@@ -506,11 +517,11 @@
mTethering.getTetherableBluetoothRegexs().length != 0) &&
mTethering.getUpstreamIfaceTypes().length != 0);
- mVpn = new Vpn(mContext, new VpnCallback());
+ mVpn = new Vpn(mContext, mVpnCallback, mNetd);
+ mVpn.startMonitoring(mContext, mTrackerHandler);
try {
mNetd.registerObserver(mTethering);
- mNetd.registerObserver(mVpn);
mNetd.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
@@ -2238,9 +2249,9 @@
*/
public void updateNetworkSettings(NetworkStateTracker nt) {
String key = nt.getTcpBufferSizesPropName();
- String bufferSizes = SystemProperties.get(key);
+ String bufferSizes = key == null ? null : SystemProperties.get(key);
- if (bufferSizes.length() == 0) {
+ if (TextUtils.isEmpty(bufferSizes)) {
if (VDBG) log(key + " not found in system properties. Using defaults");
// Setting to default values so we won't be stuck to previous values
@@ -3121,14 +3132,16 @@
}
/**
- * Start legacy VPN and return an intent to VpnDialogs. This method is
- * used by VpnSettings and not available in ConnectivityManager.
- * Permissions are checked in Vpn class.
- * @hide
+ * Start legacy VPN, controlling native daemons as needed. Creates a
+ * secondary thread to perform connection work, returning quickly.
*/
@Override
- public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
- mVpn.startLegacyVpn(config, racoon, mtpd);
+ public void startLegacyVpn(VpnProfile profile) {
+ final LinkProperties egress = getActiveLinkProperties();
+ if (egress == null) {
+ throw new IllegalStateException("Missing active network connection");
+ }
+ mVpn.startLegacyVpn(profile, mKeyStore, egress);
}
/**
@@ -3153,10 +3166,14 @@
* be done whenever a better abstraction is developed.
*/
public class VpnCallback {
-
private VpnCallback() {
}
+ public void onStateChanged(NetworkInfo info) {
+ // TODO: if connected, release delayed broadcast
+ // TODO: if disconnected, consider kicking off reconnect
+ }
+
public void override(List<String> dnsServers, List<String> searchDomains) {
if (dnsServers == null) {
restore();
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index ef09b01..f1ff27f 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
+import static android.provider.Settings.Secure.SCREENSAVER_ENABLED;
import android.content.ContentResolver;
import android.content.Context;
@@ -51,7 +52,8 @@
private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
- private static final int DEFAULT_DOCK = 1;
+ private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
+ private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
private static final int MSG_DOCK_STATE_CHANGED = 0;
@@ -214,7 +216,7 @@
Slog.w(TAG, "Unable to awaken!", e);
}
} else {
- if (isScreenSaverActivatedOnDock(mContext)) {
+ if (isScreenSaverEnabled(mContext) && isScreenSaverActivatedOnDock(mContext)) {
try {
mgr.dream();
} catch (RemoteException e) {
@@ -229,12 +231,17 @@
}
}
- private static boolean isScreenSaverActivatedOnDock(Context context) {
+ private static boolean isScreenSaverEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
- SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK) != 0;
+ SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED) != 0;
}
- private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
+ private static boolean isScreenSaverActivatedOnDock(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK) != 0;
+ }
+
+ private final Handler mHandler = new Handler(true /*async*/) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 8a564f7..23b2706 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1566,7 +1566,8 @@
MockProvider provider = new MockProvider(name, this, properties);
// remove the real provider if we are replacing GPS or network provider
if (LocationManager.GPS_PROVIDER.equals(name)
- || LocationManager.NETWORK_PROVIDER.equals(name)) {
+ || LocationManager.NETWORK_PROVIDER.equals(name)
+ || LocationManager.FUSED_PROVIDER.equals(name)) {
LocationProviderInterface p = mProvidersByName.get(name);
if (p != null) {
removeProviderLocked(p);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 39e5186..fbd45a0 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -35,6 +35,7 @@
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
+import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.Context;
import android.net.INetworkManagementEventObserver;
import android.net.InterfaceConfiguration;
@@ -55,6 +56,7 @@
import android.util.SparseBooleanArray;
import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.Preconditions;
import com.android.server.NativeDaemonConnector.Command;
import com.google.android.collect.Maps;
@@ -78,7 +80,6 @@
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
-import android.bluetooth.BluetoothTetheringDataTracker;
/**
* @hide
@@ -92,6 +93,9 @@
private static final String ADD = "add";
private static final String REMOVE = "remove";
+ private static final String ALLOW = "allow";
+ private static final String DENY = "deny";
+
private static final String DEFAULT = "default";
private static final String SECONDARY = "secondary";
@@ -169,6 +173,7 @@
private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
private volatile boolean mBandwidthControlEnabled;
+ private volatile boolean mFirewallEnabled;
/**
* Constructs a new NetworkManagementService instance
@@ -363,6 +368,9 @@
}
}
}
+
+ // TODO: Push any existing firewall state
+ setFirewallEnabled(mFirewallEnabled);
}
//
@@ -1425,7 +1433,72 @@
}
}
- /** {@inheritDoc} */
+ @Override
+ public void setFirewallEnabled(boolean enabled) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ try {
+ mConnector.execute("firewall", enabled ? "enable" : "disable");
+ mFirewallEnabled = enabled;
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public boolean isFirewallEnabled() {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ return mFirewallEnabled;
+ }
+
+ @Override
+ public void setFirewallInterfaceRule(String iface, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_interface_rule", iface, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setFirewallEgressSourceRule(String addr, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setFirewallUidRule(int uid, boolean allow) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Preconditions.checkState(mFirewallEnabled);
+ final String rule = allow ? ALLOW : DENY;
+ try {
+ mConnector.execute("firewall", "set_uid_rule", uid, rule);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
public void monitor() {
if (mConnector != null) {
mConnector.monitor();
@@ -1456,5 +1529,7 @@
}
pw.println("]");
}
+
+ pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a117b06..7097891 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -139,6 +139,7 @@
DockObserver dock = null;
UsbService usb = null;
SerialService serial = null;
+ TwilightService twilight = null;
UiModeManagerService uiMode = null;
RecognitionManagerService recognition = null;
ThrottleService throttle = null;
@@ -196,7 +197,7 @@
Slog.i(TAG, "User Service");
ServiceManager.addService(Context.USER_SERVICE,
- UserManagerService.getInstance(context));
+ UserManagerService.getInstance());
mContentResolver = context.getContentResolver();
@@ -586,9 +587,16 @@
}
try {
+ Slog.i(TAG, "Twilight Service");
+ twilight = new TwilightService(context);
+ } catch (Throwable e) {
+ reportWtf("starting TwilightService", e);
+ }
+
+ try {
Slog.i(TAG, "UI Mode Manager Service");
// Listen for UI mode changes
- uiMode = new UiModeManagerService(context);
+ uiMode = new UiModeManagerService(context, twilight);
} catch (Throwable e) {
reportWtf("starting UiModeManagerService", e);
}
@@ -733,7 +741,12 @@
w.getDefaultDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
- power.systemReady();
+ try {
+ power.systemReady(twilight);
+ } catch (Throwable e) {
+ reportWtf("making Power Manager Service ready", e);
+ }
+
try {
pm.systemReady();
} catch (Throwable e) {
@@ -750,6 +763,7 @@
final DockObserver dockF = dock;
final UsbService usbF = usb;
final ThrottleService throttleF = throttle;
+ final TwilightService twilightF = twilight;
final UiModeManagerService uiModeF = uiMode;
final AppWidgetService appWidgetF = appWidget;
final WallpaperManagerService wallpaperF = wallpaper;
@@ -810,6 +824,11 @@
reportWtf("making USB Service ready", e);
}
try {
+ if (twilightF != null) twilightF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("makin Twilight Service ready", e);
+ }
+ try {
if (uiModeF != null) uiModeF.systemReady();
} catch (Throwable e) {
reportWtf("making UI Mode Service ready", e);
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/TwilightService.java
new file mode 100644
index 0000000..a7bce54
--- /dev/null
+++ b/services/java/com/android/server/TwilightService.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2012 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 com.android.server;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.Slog;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+
+import libcore.util.Objects;
+
+/**
+ * Figures out whether it's twilight time based on the user's location.
+ *
+ * Used by the UI mode manager and other components to adjust night mode
+ * effects based on sunrise and sunset.
+ */
+public final class TwilightService {
+ private static final String TAG = "TwilightService";
+
+ private static final boolean DEBUG = false;
+
+ private static final String ACTION_UPDATE_TWILIGHT_STATE =
+ "com.android.server.action.UPDATE_TWILIGHT_STATE";
+
+ private final Context mContext;
+ private final AlarmManager mAlarmManager;
+ private final LocationManager mLocationManager;
+ private final LocationHandler mLocationHandler;
+
+ private final Object mLock = new Object();
+
+ private final ArrayList<TwilightListenerRecord> mListeners =
+ new ArrayList<TwilightListenerRecord>();
+
+ private boolean mSystemReady;
+
+ private TwilightState mTwilightState;
+
+ public TwilightService(Context context) {
+ mContext = context;
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+ mLocationHandler = new LocationHandler();
+ }
+
+ void systemReady() {
+ synchronized (mLock) {
+ mSystemReady = true;
+
+ IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
+ mContext.registerReceiver(mUpdateLocationReceiver, filter);
+
+ if (!mListeners.isEmpty()) {
+ mLocationHandler.enableLocationUpdates();
+ }
+ }
+ }
+
+ /**
+ * Gets the current twilight state.
+ *
+ * @return The current twilight state, or null if no information is available.
+ */
+ public TwilightState getCurrentState() {
+ synchronized (mLock) {
+ return mTwilightState;
+ }
+ }
+
+ /**
+ * Listens for twilight time.
+ *
+ * @param listener The listener.
+ * @param handler The handler on which to post calls into the listener.
+ */
+ public void registerListener(TwilightListener listener, Handler handler) {
+ synchronized (mLock) {
+ mListeners.add(new TwilightListenerRecord(listener, handler));
+
+ if (mSystemReady && mListeners.size() == 1) {
+ mLocationHandler.enableLocationUpdates();
+ }
+ }
+ }
+
+ private void setTwilightState(TwilightState state) {
+ synchronized (mLock) {
+ if (!Objects.equal(mTwilightState, state)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Twilight state changed: " + state);
+ }
+
+ mTwilightState = state;
+ int count = mListeners.size();
+ for (int i = 0; i < count; i++) {
+ mListeners.get(i).post();
+ }
+ }
+ }
+ }
+
+ // The user has moved if the accuracy circles of the two locations don't overlap.
+ private static boolean hasMoved(Location from, Location to) {
+ if (to == null) {
+ return false;
+ }
+
+ if (from == null) {
+ return true;
+ }
+
+ // if new location is older than the current one, the device hasn't moved.
+ if (to.getElapsedRealtimeNano() < from.getElapsedRealtimeNano()) {
+ return false;
+ }
+
+ // Get the distance between the two points.
+ float distance = from.distanceTo(to);
+
+ // Get the total accuracy radius for both locations.
+ float totalAccuracy = from.getAccuracy() + to.getAccuracy();
+
+ // If the distance is greater than the combined accuracy of the two
+ // points then they can't overlap and hence the user has moved.
+ return distance >= totalAccuracy;
+ }
+
+ /**
+ * Describes whether it is day or night.
+ * This object is immutable.
+ */
+ public static final class TwilightState {
+ private final boolean mIsNight;
+ private final long mYesterdaySunset;
+ private final long mTodaySunrise;
+ private final long mTodaySunset;
+ private final long mTomorrowSunrise;
+
+ TwilightState(boolean isNight,
+ long yesterdaySunset,
+ long todaySunrise, long todaySunset,
+ long tomorrowSunrise) {
+ mIsNight = isNight;
+ mYesterdaySunset = yesterdaySunset;
+ mTodaySunrise = todaySunrise;
+ mTodaySunset = todaySunset;
+ mTomorrowSunrise = tomorrowSunrise;
+ }
+
+ /**
+ * Returns true if it is currently night time.
+ */
+ public boolean isNight() {
+ return mIsNight;
+ }
+
+ /**
+ * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never sets.
+ */
+ public long getYesterdaySunset() {
+ return mYesterdaySunset;
+ }
+
+ /**
+ * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never rises.
+ */
+ public long getTodaySunrise() {
+ return mTodaySunrise;
+ }
+
+ /**
+ * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never sets.
+ */
+ public long getTodaySunset() {
+ return mTodaySunset;
+ }
+
+ /**
+ * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never rises.
+ */
+ public long getTomorrowSunrise() {
+ return mTomorrowSunrise;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof TwilightState && equals((TwilightState)o);
+ }
+
+ public boolean equals(TwilightState other) {
+ return other != null
+ && mIsNight == other.mIsNight
+ && mYesterdaySunset == other.mYesterdaySunset
+ && mTodaySunrise == other.mTodaySunrise
+ && mTodaySunset == other.mTodaySunset
+ && mTomorrowSunrise == other.mTomorrowSunrise;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0; // don't care
+ }
+
+ @Override
+ public String toString() {
+ DateFormat f = DateFormat.getDateTimeInstance();
+ return "{TwilightState: isNight=" + mIsNight
+ + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
+ + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
+ + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
+ + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+ + "}";
+ }
+ }
+
+ /**
+ * Listener for changes in twilight state.
+ */
+ public interface TwilightListener {
+ public void onTwilightStateChanged();
+ }
+
+ private static final class TwilightListenerRecord implements Runnable {
+ private final TwilightListener mListener;
+ private final Handler mHandler;
+
+ public TwilightListenerRecord(TwilightListener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
+
+ public void post() {
+ mHandler.post(this);
+ }
+
+ @Override
+ public void run() {
+ mListener.onTwilightStateChanged();
+ }
+ }
+
+ private final class LocationHandler extends Handler {
+ private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
+ private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
+ private static final int MSG_PROCESS_NEW_LOCATION = 3;
+ private static final int MSG_DO_TWILIGHT_UPDATE = 4;
+
+ private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
+ private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+ private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
+ private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
+ private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX =
+ 15 * DateUtils.MINUTE_IN_MILLIS;
+ private static final double FACTOR_GMT_OFFSET_LONGITUDE =
+ 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
+
+ private boolean mPassiveListenerEnabled;
+ private boolean mNetworkListenerEnabled;
+ private boolean mDidFirstInit;
+ private long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS;
+ private long mLastUpdateInterval;
+ private Location mLocation;
+ private final TwilightCalculator mTwilightCalculator = new TwilightCalculator();
+
+ public void processNewLocation(Location location) {
+ Message msg = obtainMessage(MSG_PROCESS_NEW_LOCATION, location);
+ sendMessage(msg);
+ }
+
+ public void enableLocationUpdates() {
+ sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
+ }
+
+ public void requestLocationUpdate() {
+ sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
+ }
+
+ public void requestTwilightUpdate() {
+ sendEmptyMessage(MSG_DO_TWILIGHT_UPDATE);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PROCESS_NEW_LOCATION: {
+ final Location location = (Location)msg.obj;
+ final boolean hasMoved = hasMoved(mLocation, location);
+ final boolean hasBetterAccuracy = mLocation == null
+ || location.getAccuracy() < mLocation.getAccuracy();
+ if (DEBUG) {
+ Slog.d(TAG, "Processing new location: " + location
+ + ", hasMoved=" + hasMoved
+ + ", hasBetterAccuracy=" + hasBetterAccuracy);
+ }
+ if (hasMoved || hasBetterAccuracy) {
+ setLocation(location);
+ }
+ break;
+ }
+
+ case MSG_GET_NEW_LOCATION_UPDATE:
+ if (!mNetworkListenerEnabled) {
+ // Don't do anything -- we are still trying to get a
+ // location.
+ return;
+ }
+ if ((mLastNetworkRegisterTime + MIN_LOCATION_UPDATE_MS) >=
+ SystemClock.elapsedRealtime()) {
+ // Don't do anything -- it hasn't been long enough
+ // since we last requested an update.
+ return;
+ }
+
+ // Unregister the current location monitor, so we can
+ // register a new one for it to get an immediate update.
+ mNetworkListenerEnabled = false;
+ mLocationManager.removeUpdates(mEmptyLocationListener);
+
+ // Fall through to re-register listener.
+ case MSG_ENABLE_LOCATION_UPDATES:
+ // enable network provider to receive at least location updates for a given
+ // distance.
+ boolean networkLocationEnabled;
+ try {
+ networkLocationEnabled =
+ mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+ } catch (Exception e) {
+ // we may get IllegalArgumentException if network location provider
+ // does not exist or is not yet installed.
+ networkLocationEnabled = false;
+ }
+ if (!mNetworkListenerEnabled && networkLocationEnabled) {
+ mNetworkListenerEnabled = true;
+ mLastNetworkRegisterTime = SystemClock.elapsedRealtime();
+ mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
+ LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
+
+ if (!mDidFirstInit) {
+ mDidFirstInit = true;
+ if (mLocation == null) {
+ retrieveLocation();
+ }
+ }
+ }
+
+ // enable passive provider to receive updates from location fixes (gps
+ // and network).
+ boolean passiveLocationEnabled;
+ try {
+ passiveLocationEnabled =
+ mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
+ } catch (Exception e) {
+ // we may get IllegalArgumentException if passive location provider
+ // does not exist or is not yet installed.
+ passiveLocationEnabled = false;
+ }
+
+ if (!mPassiveListenerEnabled && passiveLocationEnabled) {
+ mPassiveListenerEnabled = true;
+ mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
+ 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener);
+ }
+
+ if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) {
+ mLastUpdateInterval *= 1.5;
+ if (mLastUpdateInterval == 0) {
+ mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
+ } else if (mLastUpdateInterval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
+ mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
+ }
+ sendEmptyMessageDelayed(MSG_ENABLE_LOCATION_UPDATES, mLastUpdateInterval);
+ }
+ break;
+
+ case MSG_DO_TWILIGHT_UPDATE:
+ updateTwilightState();
+ break;
+ }
+ }
+
+ private void retrieveLocation() {
+ Location location = null;
+ final Iterator<String> providers =
+ mLocationManager.getProviders(new Criteria(), true).iterator();
+ while (providers.hasNext()) {
+ final Location lastKnownLocation =
+ mLocationManager.getLastKnownLocation(providers.next());
+ // pick the most recent location
+ if (location == null || (lastKnownLocation != null &&
+ location.getElapsedRealtimeNano() <
+ lastKnownLocation.getElapsedRealtimeNano())) {
+ location = lastKnownLocation;
+ }
+ }
+
+ // In the case there is no location available (e.g. GPS fix or network location
+ // is not available yet), the longitude of the location is estimated using the timezone,
+ // latitude and accuracy are set to get a good average.
+ if (location == null) {
+ Time currentTime = new Time();
+ currentTime.set(System.currentTimeMillis());
+ double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
+ (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
+ location = new Location("fake");
+ location.setLongitude(lngOffset);
+ location.setLatitude(0);
+ location.setAccuracy(417000.0f);
+ location.setTime(System.currentTimeMillis());
+ location.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
+
+ if (DEBUG) {
+ Slog.d(TAG, "Estimated location from timezone: " + location);
+ }
+ }
+
+ setLocation(location);
+ }
+
+ private void setLocation(Location location) {
+ mLocation = location;
+ updateTwilightState();
+ }
+
+ private void updateTwilightState() {
+ if (mLocation == null) {
+ setTwilightState(null);
+ return;
+ }
+
+ final long now = System.currentTimeMillis();
+
+ // calculate yesterday's twilight
+ mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS,
+ mLocation.getLatitude(), mLocation.getLongitude());
+ final long yesterdaySunset = mTwilightCalculator.mSunset;
+
+ // calculate today's twilight
+ mTwilightCalculator.calculateTwilight(now,
+ mLocation.getLatitude(), mLocation.getLongitude());
+ final boolean isNight = (mTwilightCalculator.mState == TwilightCalculator.NIGHT);
+ final long todaySunrise = mTwilightCalculator.mSunrise;
+ final long todaySunset = mTwilightCalculator.mSunset;
+
+ // calculate tomorrow's twilight
+ mTwilightCalculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS,
+ mLocation.getLatitude(), mLocation.getLongitude());
+ final long tomorrowSunrise = mTwilightCalculator.mSunrise;
+
+ // set twilight state
+ TwilightState state = new TwilightState(isNight, yesterdaySunset,
+ todaySunrise, todaySunset, tomorrowSunrise);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating twilight state: " + state);
+ }
+ setTwilightState(state);
+
+ // schedule next update
+ long nextUpdate = 0;
+ if (todaySunrise == -1 || todaySunset == -1) {
+ // In the case the day or night never ends the update is scheduled 12 hours later.
+ nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS;
+ } else {
+ // add some extra time to be on the safe side.
+ nextUpdate += DateUtils.MINUTE_IN_MILLIS;
+
+ if (now > todaySunset) {
+ nextUpdate += tomorrowSunrise;
+ } else if (now > todaySunrise) {
+ nextUpdate += todaySunset;
+ } else {
+ nextUpdate += todaySunrise;
+ }
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Next update in " + (nextUpdate - now) + " ms");
+ }
+
+ Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+ mAlarmManager.cancel(pendingIntent);
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
+ }
+ };
+
+ private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())
+ && !intent.getBooleanExtra("state", false)) {
+ // Airplane mode is now off!
+ mLocationHandler.requestLocationUpdate();
+ return;
+ }
+
+ // Time zone has changed or alarm expired.
+ mLocationHandler.requestTwilightUpdate();
+ }
+ };
+
+ // A LocationListener to initialize the network location provider. The location updates
+ // are handled through the passive location provider.
+ private final LocationListener mEmptyLocationListener = new LocationListener() {
+ public void onLocationChanged(Location location) {
+ }
+
+ public void onProviderDisabled(String provider) {
+ }
+
+ public void onProviderEnabled(String provider) {
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+ };
+
+ private final LocationListener mLocationListener = new LocationListener() {
+ public void onLocationChanged(Location location) {
+ mLocationHandler.processNewLocation(location);
+ }
+
+ public void onProviderDisabled(String provider) {
+ }
+
+ public void onProviderEnabled(String provider) {
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+ };
+}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 5299b71..617b29d 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
import android.app.IUiModeManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -32,55 +31,33 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
import android.os.BatteryManager;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
-import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.text.format.Time;
import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Iterator;
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
+import com.android.server.TwilightService.TwilightState;
class UiModeManagerService extends IUiModeManager.Stub {
private static final String TAG = UiModeManager.class.getSimpleName();
private static final boolean LOG = false;
- private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL";
-
// Enable launching of applications when entering the dock.
private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
- private static final int MSG_UPDATE_TWILIGHT = 0;
- private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
- private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
-
- private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
- private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
- private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
- private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
- private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 15 * DateUtils.MINUTE_IN_MILLIS;
- private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
-
- private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE";
-
private final Context mContext;
+ private final TwilightService mTwilightService;
+ private final Handler mHandler = new Handler();
final Object mLock = new Object();
@@ -106,10 +83,6 @@
private NotificationManager mNotificationManager;
- private AlarmManager mAlarmManager;
-
- private LocationManager mLocationManager;
- private Location mLocation;
private StatusBarManager mStatusBarManager;
private final PowerManager.WakeLock mWakeLock;
@@ -206,15 +179,6 @@
}
};
- private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
- }
- }
- };
-
private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -236,113 +200,24 @@
}
};
- private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+ private final TwilightService.TwilightListener mTwilightListener =
+ new TwilightService.TwilightListener() {
@Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
- if (!intent.getBooleanExtra("state", false)) {
- // Airplane mode is now off!
- mHandler.sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
- }
- } else {
- // Time zone has changed!
- mHandler.sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
- }
+ public void onTwilightStateChanged() {
+ updateTwilight();
}
};
- // A LocationListener to initialize the network location provider. The location updates
- // are handled through the passive location provider.
- private final LocationListener mEmptyLocationListener = new LocationListener() {
- public void onLocationChanged(Location location) {
- }
-
- public void onProviderDisabled(String provider) {
- }
-
- public void onProviderEnabled(String provider) {
- }
-
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
- };
-
- private final LocationListener mLocationListener = new LocationListener() {
-
- public void onLocationChanged(Location location) {
- final boolean hasMoved = hasMoved(location);
- final boolean hasBetterAccuracy = mLocation == null
- || location.getAccuracy() < mLocation.getAccuracy();
- if (hasMoved || hasBetterAccuracy) {
- synchronized (mLock) {
- mLocation = location;
- if (hasMoved && isDoingNightMode()
- && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
- }
- }
- }
- }
-
- public void onProviderDisabled(String provider) {
- }
-
- public void onProviderEnabled(String provider) {
- }
-
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
-
- /*
- * The user has moved if the accuracy circles of the two locations
- * don't overlap.
- */
- private boolean hasMoved(Location location) {
- if (location == null) {
- return false;
- }
- if (mLocation == null) {
- return true;
- }
-
- /* if new location is older than the current one, the devices hasn't
- * moved.
- */
- if (location.getElapsedRealtimeNano() < mLocation.getElapsedRealtimeNano()) {
- return false;
- }
-
- /* Get the distance between the two points */
- float distance = mLocation.distanceTo(location);
-
- /* Get the total accuracy radius for both locations */
- float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy();
-
- /* If the distance is greater than the combined accuracy of the two
- * points then they can't overlap and hence the user has moved.
- */
- return distance >= totalAccuracy;
- }
- };
-
- public UiModeManagerService(Context context) {
+ public UiModeManagerService(Context context, TwilightService twilight) {
mContext = context;
+ mTwilightService = twilight;
ServiceManager.addService(Context.UI_MODE_SERVICE, this);
- mAlarmManager =
- (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
- mLocationManager =
- (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
- mContext.registerReceiver(mTwilightUpdateReceiver,
- new IntentFilter(ACTION_UPDATE_NIGHT_MODE));
mContext.registerReceiver(mDockModeReceiver,
new IntentFilter(Intent.ACTION_DOCK_EVENT));
mContext.registerReceiver(mBatteryReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- mContext.registerReceiver(mUpdateLocationReceiver, filter);
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
@@ -360,6 +235,8 @@
mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
+
+ mTwilightService.registerListener(mTwilightListener, mHandler);
}
public void disableCarMode(int flags) {
@@ -419,8 +296,8 @@
synchronized (mLock) {
mSystemReady = true;
mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+ updateComputedNightModeLocked();
updateLocked(0, 0);
- mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
}
}
@@ -467,7 +344,7 @@
}
if (mCarModeEnabled) {
if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- updateTwilightLocked();
+ updateComputedNightModeLocked();
uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
: Configuration.UI_MODE_NIGHT_NO;
} else {
@@ -651,191 +528,20 @@
}
}
- private final Handler mHandler = new Handler() {
-
- boolean mPassiveListenerEnabled;
- boolean mNetworkListenerEnabled;
- boolean mDidFirstInit;
- long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS;
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_TWILIGHT:
- synchronized (mLock) {
- if (isDoingNightMode() && mLocation != null
- && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- updateTwilightLocked();
- updateLocked(0, 0);
- }
- }
- break;
- case MSG_GET_NEW_LOCATION_UPDATE:
- if (!mNetworkListenerEnabled) {
- // Don't do anything -- we are still trying to get a
- // location.
- return;
- }
- if ((mLastNetworkRegisterTime+MIN_LOCATION_UPDATE_MS)
- >= SystemClock.elapsedRealtime()) {
- // Don't do anything -- it hasn't been long enough
- // since we last requested an update.
- return;
- }
-
- // Unregister the current location monitor, so we can
- // register a new one for it to get an immediate update.
- mNetworkListenerEnabled = false;
- mLocationManager.removeUpdates(mEmptyLocationListener);
-
- // Fall through to re-register listener.
- case MSG_ENABLE_LOCATION_UPDATES:
- // enable network provider to receive at least location updates for a given
- // distance.
- boolean networkLocationEnabled;
- try {
- networkLocationEnabled =
- mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
- } catch (Exception e) {
- // we may get IllegalArgumentException if network location provider
- // does not exist or is not yet installed.
- networkLocationEnabled = false;
- }
- if (!mNetworkListenerEnabled && networkLocationEnabled) {
- mNetworkListenerEnabled = true;
- mLastNetworkRegisterTime = SystemClock.elapsedRealtime();
- mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
- LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
-
- if (!mDidFirstInit) {
- mDidFirstInit = true;
- if (mLocation == null) {
- retrieveLocation();
- }
- synchronized (mLock) {
- if (isDoingNightMode() && mLocation != null
- && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
- updateTwilightLocked();
- updateLocked(0, 0);
- }
- }
- }
- }
- // enable passive provider to receive updates from location fixes (gps
- // and network).
- boolean passiveLocationEnabled;
- try {
- passiveLocationEnabled =
- mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
- } catch (Exception e) {
- // we may get IllegalArgumentException if passive location provider
- // does not exist or is not yet installed.
- passiveLocationEnabled = false;
- }
- if (!mPassiveListenerEnabled && passiveLocationEnabled) {
- mPassiveListenerEnabled = true;
- mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
- 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener);
- }
- if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) {
- long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL);
- interval *= 1.5;
- if (interval == 0) {
- interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
- } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
- interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
- }
- Bundle bundle = new Bundle();
- bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval);
- Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES);
- newMsg.setData(bundle);
- mHandler.sendMessageDelayed(newMsg, interval);
- }
- break;
+ private void updateTwilight() {
+ synchronized (mLock) {
+ if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ updateComputedNightModeLocked();
+ updateLocked(0, 0);
}
}
+ }
- private void retrieveLocation() {
- Location location = null;
- final Iterator<String> providers =
- mLocationManager.getProviders(new Criteria(), true).iterator();
- while (providers.hasNext()) {
- final Location lastKnownLocation =
- mLocationManager.getLastKnownLocation(providers.next());
- // pick the most recent location
- if (location == null || (lastKnownLocation != null &&
- location.getElapsedRealtimeNano() <
- lastKnownLocation.getElapsedRealtimeNano())) {
- location = lastKnownLocation;
- }
- }
- // In the case there is no location available (e.g. GPS fix or network location
- // is not available yet), the longitude of the location is estimated using the timezone,
- // latitude and accuracy are set to get a good average.
- if (location == null) {
- Time currentTime = new Time();
- currentTime.set(System.currentTimeMillis());
- double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
- (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
- location = new Location("fake");
- location.setLongitude(lngOffset);
- location.setLatitude(0);
- location.setAccuracy(417000.0f);
- location.setTime(System.currentTimeMillis());
- location.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
- }
- synchronized (mLock) {
- mLocation = location;
- }
+ private void updateComputedNightModeLocked() {
+ TwilightState state = mTwilightService.getCurrentState();
+ if (state != null) {
+ mComputedNightMode = state.isNight();
}
- };
-
- void updateTwilightLocked() {
- if (mLocation == null) {
- return;
- }
- final long currentTime = System.currentTimeMillis();
- boolean nightMode;
- // calculate current twilight
- TwilightCalculator tw = new TwilightCalculator();
- tw.calculateTwilight(currentTime,
- mLocation.getLatitude(), mLocation.getLongitude());
- if (tw.mState == TwilightCalculator.DAY) {
- nightMode = false;
- } else {
- nightMode = true;
- }
-
- // schedule next update
- long nextUpdate = 0;
- if (tw.mSunrise == -1 || tw.mSunset == -1) {
- // In the case the day or night never ends the update is scheduled 12 hours later.
- nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS;
- } else {
- final int mLastTwilightState = tw.mState;
- // add some extra time to be on the save side.
- nextUpdate += DateUtils.MINUTE_IN_MILLIS;
- if (currentTime > tw.mSunset) {
- // next update should be on the following day
- tw.calculateTwilight(currentTime
- + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
- mLocation.getLongitude());
- }
-
- if (mLastTwilightState == TwilightCalculator.NIGHT) {
- nextUpdate += tw.mSunrise;
- } else {
- nextUpdate += tw.mSunset;
- }
- }
-
- Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE);
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
- mAlarmManager.cancel(pendingIntent);
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
-
- mComputedNightMode = nightMode;
}
@Override
@@ -860,9 +566,8 @@
pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
pw.print(" mSystemReady="); pw.println(mSystemReady);
- if (mLocation != null) {
- pw.print(" mLocation="); pw.println(mLocation);
- }
+ pw.print(" mTwilightService.getCurrentState()=");
+ pw.println(mTwilightService.getCurrentState());
}
}
}
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index b609867..72fde11 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -441,7 +441,7 @@
private void delay(long duration) {
if (duration > 0) {
- long bedtime = SystemClock.uptimeMillis();
+ long bedtime = duration + SystemClock.uptimeMillis();
do {
try {
this.wait(duration);
@@ -451,8 +451,7 @@
if (mDone) {
break;
}
- duration = duration
- - SystemClock.uptimeMillis() - bedtime;
+ duration = bedtime - SystemClock.uptimeMillis();
} while (duration > 0);
}
}
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index e222936..e6bcaa1 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -210,7 +210,7 @@
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
- int callingPid, int callingUid) {
+ int callingPid, int callingUid, int userId) {
if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -226,7 +226,7 @@
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- callingPid, callingUid, UserHandle.getUserId(callingUid), true);
+ callingPid, callingUid, userId, true);
if (res == null) {
return null;
}
@@ -264,7 +264,7 @@
}
int stopServiceLocked(IApplicationThread caller, Intent service,
- String resolvedType) {
+ String resolvedType, int userId) {
if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
+ " type=" + resolvedType);
@@ -278,9 +278,7 @@
// If this service is active, make sure it is stopped.
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getCallingUid(),
- callerApp == null ? UserHandle.getCallingUserId() : callerApp.userId,
- false);
+ Binder.getCallingPid(), Binder.getCallingUid(), userId, false);
if (r != null) {
if (r.record != null) {
final long origId = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7f2b69f..2b4f8b1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -105,6 +105,7 @@
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.SELinux;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -1982,18 +1983,13 @@
try {
final PackageManager pm = mContext.getPackageManager();
gids = pm.getPackageGids(app.info.packageName);
- if (pm.checkPermission(
- android.Manifest.permission.READ_EXTERNAL_STORAGE, app.info.packageName)
- == PERMISSION_GRANTED) {
- if (Environment.isExternalStorageEmulated()) {
- mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
- } else {
- mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
- }
- }
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
+
+ if (Environment.isExternalStorageEmulated()) {
+ mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
+ }
}
if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
@@ -3040,7 +3036,12 @@
File tracesFile = new File(tracesPath);
try {
File tracesDir = tracesFile.getParentFile();
- if (!tracesDir.exists()) tracesFile.mkdirs();
+ if (!tracesDir.exists()) {
+ tracesFile.mkdirs();
+ if (!SELinux.restorecon(tracesDir)) {
+ return null;
+ }
+ }
FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
if (clearTraces && tracesFile.exists()) tracesFile.delete();
@@ -3144,7 +3145,12 @@
final File tracesDir = tracesFile.getParentFile();
final File tracesTmp = new File(tracesDir, "__tmp__");
try {
- if (!tracesDir.exists()) tracesFile.mkdirs();
+ if (!tracesDir.exists()) {
+ tracesFile.mkdirs();
+ if (!SELinux.restorecon(tracesDir.getPath())) {
+ return;
+ }
+ }
FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
if (tracesFile.exists()) {
@@ -10548,7 +10554,7 @@
}
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType) {
+ String resolvedType, int userId) {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
@@ -10560,9 +10566,10 @@
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
+ checkValidCaller(callingUid, userId);
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
- resolvedType, callingPid, callingUid);
+ resolvedType, callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -10575,22 +10582,24 @@
Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType);
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid);
+ resolvedType, -1, uid, UserHandle.getUserId(uid));
Binder.restoreCallingIdentity(origId);
return res;
}
}
public int stopService(IApplicationThread caller, Intent service,
- String resolvedType) {
+ String resolvedType, int userId) {
enforceNotIsolatedCaller("stopService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ checkValidCaller(Binder.getCallingUid(), userId);
+
synchronized(this) {
- return mServices.stopServiceLocked(caller, service, resolvedType);
+ return mServices.stopServiceLocked(caller, service, resolvedType, userId);
}
}
diff --git a/services/java/com/android/server/am/DeviceMonitor.java b/services/java/com/android/server/am/DeviceMonitor.java
index 5f3b0ce..21e7252 100644
--- a/services/java/com/android/server/am/DeviceMonitor.java
+++ b/services/java/com/android/server/am/DeviceMonitor.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.os.SELinux;
import android.util.Slog;
import java.io.*;
@@ -80,6 +81,9 @@
if (!BASE.isDirectory() && !BASE.mkdirs()) {
throw new AssertionError("Couldn't create " + BASE + ".");
}
+ if (!SELinux.restorecon(BASE)) {
+ throw new AssertionError("Couldn't restorecon " + BASE + ".");
+ }
}
private static final File[] PATHS = {
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 1232846..d96bd0d 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -16,8 +16,11 @@
package com.android.server.connectivity;
+import static android.Manifest.permission.BIND_VPN_SERVICE;
+
import android.app.Notification;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -28,27 +31,43 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.net.BaseNetworkStateTracker;
+import android.net.ConnectivityManager;
import android.net.INetworkManagementEventObserver;
+import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
+import android.net.NetworkInfo;
+import android.net.RouteInfo;
+import android.net.NetworkInfo.DetailedState;
import android.os.Binder;
import android.os.FileUtils;
import android.os.IBinder;
+import android.os.INetworkManagementService;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemService;
+import android.security.Credentials;
+import android.security.KeyStore;
import android.util.Log;
+import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.internal.util.Preconditions;
import com.android.server.ConnectivityService.VpnCallback;
+import com.android.server.net.BaseNetworkObserver;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.Inet4Address;
+import java.net.InetAddress;
import java.nio.charset.Charsets;
import java.util.Arrays;
@@ -57,24 +76,63 @@
/**
* @hide
*/
-public class Vpn extends INetworkManagementEventObserver.Stub {
+public class Vpn extends BaseNetworkStateTracker {
+ private static final String TAG = "Vpn";
+ private static final boolean LOGD = true;
+
+ // TODO: create separate trackers for each unique VPN to support
+ // automated reconnection
- private final static String TAG = "Vpn";
-
- private final static String BIND_VPN_SERVICE =
- android.Manifest.permission.BIND_VPN_SERVICE;
-
- private final Context mContext;
private final VpnCallback mCallback;
private String mPackage = VpnConfig.LEGACY_VPN;
private String mInterface;
private Connection mConnection;
private LegacyVpnRunner mLegacyVpnRunner;
+ private PendingIntent mStatusIntent;
- public Vpn(Context context, VpnCallback callback) {
+ public Vpn(Context context, VpnCallback callback, INetworkManagementService netService) {
+ // TODO: create dedicated TYPE_VPN network type
+ super(ConnectivityManager.TYPE_DUMMY);
mContext = context;
mCallback = callback;
+
+ try {
+ netService.registerObserver(mObserver);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Problem registering observer", e);
+ }
+ }
+
+ @Override
+ protected void startMonitoringInternal() {
+ // Ignored; events are sent through callbacks for now
+ }
+
+ @Override
+ public boolean teardown() {
+ // TODO: finish migration to unique tracker for each VPN
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean reconnect() {
+ // TODO: finish migration to unique tracker for each VPN
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getTcpBufferSizesPropName() {
+ return PROP_TCP_BUFFER_UNKNOWN;
+ }
+
+ /**
+ * Update current state, dispaching event to listeners.
+ */
+ private void updateState(DetailedState detailedState, String reason) {
+ if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
+ mNetworkInfo.setDetailedState(detailedState, reason, null);
+ mCallback.onStateChanged(new NetworkInfo(mNetworkInfo));
}
/**
@@ -113,10 +171,13 @@
// Reset the interface and hide the notification.
if (mInterface != null) {
jniReset(mInterface);
- long identity = Binder.clearCallingIdentity();
- mCallback.restore();
- hideNotification();
- Binder.restoreCallingIdentity(identity);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.restore();
+ hideNotification();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
mInterface = null;
}
@@ -137,6 +198,7 @@
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
mPackage = newPackage;
+ updateState(DetailedState.IDLE, "prepare");
return true;
}
@@ -145,7 +207,7 @@
* interface. The socket is NOT closed by this method.
*
* @param socket The socket to be bound.
- * @param name The name of the interface.
+ * @param interfaze The name of the interface.
*/
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
PackageManager pm = mContext.getPackageManager();
@@ -209,6 +271,7 @@
// Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
try {
+ updateState(DetailedState.CONNECTING, "establish");
String interfaze = jniGetName(tun.getFd());
if (jniSetAddresses(interfaze, config.addresses) < 1) {
throw new IllegalArgumentException("At least one address must be specified");
@@ -229,6 +292,7 @@
mConnection = connection;
mInterface = interfaze;
} catch (RuntimeException e) {
+ updateState(DetailedState.FAILED, "establish");
IoUtils.closeQuietly(tun);
throw e;
}
@@ -239,57 +303,61 @@
config.interfaze = mInterface;
// Override DNS servers and show the notification.
- long identity = Binder.clearCallingIdentity();
- mCallback.override(config.dnsServers, config.searchDomains);
- showNotification(config, label, bitmap);
- Binder.restoreCallingIdentity(identity);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.override(config.dnsServers, config.searchDomains);
+ showNotification(config, label, bitmap);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ // TODO: ensure that contract class eventually marks as connected
+ updateState(DetailedState.AUTHENTICATING, "establish");
return tun;
}
- // INetworkManagementEventObserver.Stub
- @Override
- public void interfaceAdded(String interfaze) {
- }
-
- // INetworkManagementEventObserver.Stub
- @Override
- public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
- if (!up && mLegacyVpnRunner != null) {
- mLegacyVpnRunner.check(interfaze);
+ @Deprecated
+ public synchronized void interfaceStatusChanged(String iface, boolean up) {
+ try {
+ mObserver.interfaceStatusChanged(iface, up);
+ } catch (RemoteException e) {
+ // ignored; target is local
}
}
- // INetworkManagementEventObserver.Stub
- @Override
- public void interfaceLinkStateChanged(String interfaze, boolean up) {
- }
-
- // INetworkManagementEventObserver.Stub
- @Override
- public synchronized void interfaceRemoved(String interfaze) {
- if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
- long identity = Binder.clearCallingIdentity();
- mCallback.restore();
- hideNotification();
- Binder.restoreCallingIdentity(identity);
- mInterface = null;
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
- } else if (mLegacyVpnRunner != null) {
- mLegacyVpnRunner.exit();
- mLegacyVpnRunner = null;
+ private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
+ @Override
+ public void interfaceStatusChanged(String interfaze, boolean up) {
+ synchronized (Vpn.this) {
+ if (!up && mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.check(interfaze);
+ }
}
}
- }
- // INetworkManagementEventObserver.Stub
- @Override
- public void limitReached(String limit, String interfaze) {
- }
-
- public void interfaceClassDataActivityChanged(String label, boolean active) {
- }
+ @Override
+ public void interfaceRemoved(String interfaze) {
+ synchronized (Vpn.this) {
+ if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.restore();
+ hideNotification();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ mInterface = null;
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ updateState(DetailedState.DISCONNECTED, "interfaceRemoved");
+ } else if (mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.exit();
+ mLegacyVpnRunner = null;
+ }
+ }
+ }
+ }
+ };
private void enforceControlPermission() {
// System user is allowed to control VPN.
@@ -326,6 +394,8 @@
}
private void showNotification(VpnConfig config, String label, Bitmap icon) {
+ mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext, config);
+
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -341,15 +411,17 @@
.setLargeIcon(icon)
.setContentTitle(title)
.setContentText(text)
- .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config))
+ .setContentIntent(mStatusIntent)
.setDefaults(0)
.setOngoing(true)
- .getNotification();
+ .build();
nm.notify(R.drawable.vpn_connected, notification);
}
}
private void hideNotification() {
+ mStatusIntent = null;
+
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -366,31 +438,164 @@
private native int jniCheck(String interfaze);
private native void jniProtect(int socket, String interfaze);
+ private static String findLegacyVpnGateway(LinkProperties prop) {
+ for (RouteInfo route : prop.getRoutes()) {
+ // Currently legacy VPN only works on IPv4.
+ if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
+ return route.getGateway().getHostAddress();
+ }
+ }
+
+ throw new IllegalStateException("Unable to find suitable gateway");
+ }
+
/**
- * Start legacy VPN. This method stops the daemons and restart them
- * if arguments are not null. Heavy things are offloaded to another
- * thread, so callers will not be blocked for a long time.
- *
- * @param config The parameters to configure the network.
- * @param raoocn The arguments to be passed to racoon.
- * @param mtpd The arguments to be passed to mtpd.
+ * Start legacy VPN, controlling native daemons as needed. Creates a
+ * secondary thread to perform connection work, returning quickly.
*/
- public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
+ if (keyStore.state() != KeyStore.State.UNLOCKED) {
+ throw new IllegalStateException("KeyStore isn't unlocked");
+ }
+
+ final String iface = egress.getInterfaceName();
+ final String gateway = findLegacyVpnGateway(egress);
+
+ // Load certificates.
+ String privateKey = "";
+ String userCert = "";
+ String caCert = "";
+ String serverCert = "";
+ if (!profile.ipsecUserCert.isEmpty()) {
+ privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
+ byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
+ userCert = (value == null) ? null : new String(value, Charsets.UTF_8);
+ }
+ if (!profile.ipsecCaCert.isEmpty()) {
+ byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
+ caCert = (value == null) ? null : new String(value, Charsets.UTF_8);
+ }
+ if (!profile.ipsecServerCert.isEmpty()) {
+ byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
+ serverCert = (value == null) ? null : new String(value, Charsets.UTF_8);
+ }
+ if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
+ throw new IllegalStateException("Cannot load credentials");
+ }
+
+ // Prepare arguments for racoon.
+ String[] racoon = null;
+ switch (profile.type) {
+ case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+ racoon = new String[] {
+ iface, profile.server, "udppsk", profile.ipsecIdentifier,
+ profile.ipsecSecret, "1701",
+ };
+ break;
+ case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+ racoon = new String[] {
+ iface, profile.server, "udprsa", privateKey, userCert,
+ caCert, serverCert, "1701",
+ };
+ break;
+ case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+ racoon = new String[] {
+ iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
+ profile.ipsecSecret, profile.username, profile.password, "", gateway,
+ };
+ break;
+ case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+ racoon = new String[] {
+ iface, profile.server, "xauthrsa", privateKey, userCert,
+ caCert, serverCert, profile.username, profile.password, "", gateway,
+ };
+ break;
+ case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+ racoon = new String[] {
+ iface, profile.server, "hybridrsa",
+ caCert, serverCert, profile.username, profile.password, "", gateway,
+ };
+ break;
+ }
+
+ // Prepare arguments for mtpd.
+ String[] mtpd = null;
+ switch (profile.type) {
+ case VpnProfile.TYPE_PPTP:
+ mtpd = new String[] {
+ iface, "pptp", profile.server, "1723",
+ "name", profile.username, "password", profile.password,
+ "linkname", "vpn", "refuse-eap", "nodefaultroute",
+ "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
+ (profile.mppe ? "+mppe" : "nomppe"),
+ };
+ break;
+ case VpnProfile.TYPE_L2TP_IPSEC_PSK:
+ case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+ mtpd = new String[] {
+ iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
+ "name", profile.username, "password", profile.password,
+ "linkname", "vpn", "refuse-eap", "nodefaultroute",
+ "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
+ };
+ break;
+ }
+
+ VpnConfig config = new VpnConfig();
+ config.legacy = true;
+ config.user = profile.key;
+ config.interfaze = iface;
+ config.session = profile.name;
+ config.routes = profile.routes;
+ if (!profile.dnsServers.isEmpty()) {
+ config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
+ }
+ if (!profile.searchDomains.isEmpty()) {
+ config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
+ }
+
+ startLegacyVpn(config, racoon, mtpd);
+ }
+
+ private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ stopLegacyVpn();
+
// Prepare for the new request. This also checks the caller.
prepare(null, VpnConfig.LEGACY_VPN);
+ updateState(DetailedState.CONNECTING, "startLegacyVpn");
// Start a new LegacyVpnRunner and we are done!
mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
mLegacyVpnRunner.start();
}
+ public synchronized void stopLegacyVpn() {
+ if (mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.exit();
+ mLegacyVpnRunner = null;
+
+ synchronized (LegacyVpnRunner.TAG) {
+ // wait for old thread to completely finish before spinning up
+ // new instance, otherwise state updates can be out of order.
+ }
+ }
+ }
+
/**
* Return the information of the current ongoing legacy VPN.
*/
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Check if the caller is authorized.
enforceControlPermission();
- return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
+ if (mLegacyVpnRunner == null) return null;
+
+ final LegacyVpnInfo info = new LegacyVpnInfo();
+ info.key = mLegacyVpnRunner.mConfig.user;
+ info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
+ if (mNetworkInfo.isConnected()) {
+ info.intent = mStatusIntent;
+ }
+ return info;
}
/**
@@ -407,8 +612,6 @@
private final String[] mDaemons;
private final String[][] mArguments;
private final LocalSocket[] mSockets;
- private final String mOuterInterface;
- private final LegacyVpnInfo mInfo;
private long mTimer = -1;
@@ -416,20 +619,13 @@
super(TAG);
mConfig = config;
mDaemons = new String[] {"racoon", "mtpd"};
+ // TODO: clear arguments from memory once launched
mArguments = new String[][] {racoon, mtpd};
mSockets = new LocalSocket[mDaemons.length];
- mInfo = new LegacyVpnInfo();
-
- // This is the interface which VPN is running on.
- mOuterInterface = mConfig.interfaze;
-
- // Legacy VPN is not a real package, so we use it to carry the key.
- mInfo.key = mConfig.user;
- mConfig.user = VpnConfig.LEGACY_VPN;
}
public void check(String interfaze) {
- if (interfaze.equals(mOuterInterface)) {
+ if (interfaze.equals(mConfig.interfaze)) {
Log.i(TAG, "Legacy VPN is going down with " + interfaze);
exit();
}
@@ -441,15 +637,7 @@
for (LocalSocket socket : mSockets) {
IoUtils.closeQuietly(socket);
}
- }
-
- public LegacyVpnInfo getInfo() {
- // Update the info when VPN is disconnected.
- if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) {
- mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
- mInfo.intent = null;
- }
- return mInfo;
+ updateState(DetailedState.DISCONNECTED, "exit");
}
@Override
@@ -459,6 +647,7 @@
synchronized (TAG) {
Log.v(TAG, "Executing");
execute();
+ monitorDaemons();
}
}
@@ -470,17 +659,17 @@
} else if (now - mTimer <= 60000) {
Thread.sleep(yield ? 200 : 1);
} else {
- mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
+ updateState(DetailedState.FAILED, "checkpoint");
throw new IllegalStateException("Time is up");
}
}
private void execute() {
// Catch all exceptions so we can clean up few things.
+ boolean initFinished = false;
try {
// Initialize the timer.
checkpoint(false);
- mInfo.state = LegacyVpnInfo.STATE_INITIALIZING;
// Wait for the daemons to stop.
for (String daemon : mDaemons) {
@@ -496,6 +685,7 @@
throw new IllegalStateException("Cannot delete the state");
}
new File("/data/misc/vpn/abort").delete();
+ initFinished = true;
// Check if we need to restart any of the daemons.
boolean restart = false;
@@ -503,10 +693,10 @@
restart = restart || (arguments != null);
}
if (!restart) {
- mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
+ updateState(DetailedState.DISCONNECTED, "execute");
return;
}
- mInfo.state = LegacyVpnInfo.STATE_CONNECTING;
+ updateState(DetailedState.CONNECTING, "execute");
// Start the daemon with arguments.
for (int i = 0; i < mDaemons.length; ++i) {
@@ -633,26 +823,53 @@
showNotification(mConfig, null, null);
Log.i(TAG, "Connected!");
- mInfo.state = LegacyVpnInfo.STATE_CONNECTED;
- mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null);
+ updateState(DetailedState.CONNECTED, "execute");
}
} catch (Exception e) {
Log.i(TAG, "Aborting", e);
exit();
} finally {
// Kill the daemons if they fail to stop.
- if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) {
+ if (!initFinished) {
for (String daemon : mDaemons) {
SystemService.stop(daemon);
}
}
// Do not leave an unstable state.
- if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING ||
- mInfo.state == LegacyVpnInfo.STATE_CONNECTING) {
- mInfo.state = LegacyVpnInfo.STATE_FAILED;
+ if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
+ updateState(DetailedState.FAILED, "execute");
}
}
}
+
+ /**
+ * Monitor the daemons we started, moving to disconnected state if the
+ * underlying services fail.
+ */
+ private void monitorDaemons() {
+ if (!mNetworkInfo.isConnected()) {
+ return;
+ }
+
+ try {
+ while (true) {
+ Thread.sleep(2000);
+ for (int i = 0; i < mDaemons.length; i++) {
+ if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
+ return;
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
+ } finally {
+ for (String daemon : mDaemons) {
+ SystemService.stop(daemon);
+ }
+
+ updateState(DetailedState.DISCONNECTED, "babysit");
+ }
+ }
}
}
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 0b8ff62..29c68eb 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -1438,6 +1438,10 @@
* Private handler for the input manager.
*/
private final class InputManagerHandler extends Handler {
+ public InputManagerHandler() {
+ super(true /*async*/);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 8d7e92a..c2c0a71 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -35,6 +35,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -164,6 +165,8 @@
private static final int UPDATE_LOCATION = 7;
private static final int ADD_LISTENER = 8;
private static final int REMOVE_LISTENER = 9;
+ private static final int INJECT_NTP_TIME_FINISHED = 10;
+ private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
// Request setid
private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
@@ -229,10 +232,15 @@
// true if we have network connectivity
private boolean mNetworkAvailable;
+ // states for injecting ntp and downloading xtra data
+ private static final int STATE_PENDING_NETWORK = 0;
+ private static final int STATE_DOWNLOADING = 1;
+ private static final int STATE_IDLE = 2;
+
// flags to trigger NTP or XTRA data download when network becomes available
// initialized to true so we do NTP and XTRA when the network comes up after booting
- private boolean mInjectNtpTimePending = true;
- private boolean mDownloadXtraDataPending = true;
+ private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
+ private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
// set to true if the GPS engine does not do on-demand NTP time requests
private boolean mPeriodicTimeInjection;
@@ -496,6 +504,7 @@
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ALARM_WAKEUP);
intentFilter.addAction(ALARM_TIMEOUT);
+ intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mBroadcastReciever, intentFilter);
}
@@ -568,81 +577,111 @@
}
if (mNetworkAvailable) {
- if (mInjectNtpTimePending) {
+ if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
sendMessage(INJECT_NTP_TIME, 0, null);
}
- if (mDownloadXtraDataPending) {
+ if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
}
}
}
private void handleInjectNtpTime() {
- if (!mNetworkAvailable) {
- // try again when network is up
- mInjectNtpTimePending = true;
+ if (mInjectNtpTimePending == STATE_DOWNLOADING) {
+ // already downloading data
return;
}
- mInjectNtpTimePending = false;
-
- long delay;
-
- // force refresh NTP cache when outdated
- if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
- mNtpTime.forceRefresh();
+ if (!mNetworkAvailable) {
+ // try again when network is up
+ mInjectNtpTimePending = STATE_PENDING_NETWORK;
+ return;
}
+ mInjectNtpTimePending = STATE_DOWNLOADING;
- // only update when NTP time is fresh
- if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
- long time = mNtpTime.getCachedNtpTime();
- long timeReference = mNtpTime.getCachedNtpTimeReference();
- long certainty = mNtpTime.getCacheCertainty();
- long now = System.currentTimeMillis();
+ // hold wake lock while task runs
+ mWakeLock.acquire();
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ long delay;
- Log.d(TAG, "NTP server returned: "
- + time + " (" + new Date(time)
- + ") reference: " + timeReference
- + " certainty: " + certainty
- + " system time offset: " + (time - now));
+ // force refresh NTP cache when outdated
+ if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
+ mNtpTime.forceRefresh();
+ }
- native_inject_time(time, timeReference, (int) certainty);
- delay = NTP_INTERVAL;
- } else {
- if (DEBUG) Log.d(TAG, "requestTime failed");
- delay = RETRY_INTERVAL;
- }
+ // only update when NTP time is fresh
+ if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
+ long time = mNtpTime.getCachedNtpTime();
+ long timeReference = mNtpTime.getCachedNtpTimeReference();
+ long certainty = mNtpTime.getCacheCertainty();
+ long now = System.currentTimeMillis();
- if (mPeriodicTimeInjection) {
- // send delayed message for next NTP injection
- // since this is delayed and not urgent we do not hold a wake lock here
- mHandler.removeMessages(INJECT_NTP_TIME);
- mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
- }
+ Log.d(TAG, "NTP server returned: "
+ + time + " (" + new Date(time)
+ + ") reference: " + timeReference
+ + " certainty: " + certainty
+ + " system time offset: " + (time - now));
+
+ native_inject_time(time, timeReference, (int) certainty);
+ delay = NTP_INTERVAL;
+ } else {
+ if (DEBUG) Log.d(TAG, "requestTime failed");
+ delay = RETRY_INTERVAL;
+ }
+
+ sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
+
+ if (mPeriodicTimeInjection) {
+ // send delayed message for next NTP injection
+ // since this is delayed and not urgent we do not hold a wake lock here
+ mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
+ }
+
+ // release wake lock held by task
+ mWakeLock.release();
+ }
+ });
}
private void handleDownloadXtraData() {
- if (!mNetworkAvailable) {
- // try again when network is up
- mDownloadXtraDataPending = true;
+ if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
+ // already downloading data
return;
}
- mDownloadXtraDataPending = false;
-
-
- GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
- byte[] data = xtraDownloader.downloadXtraData();
- if (data != null) {
- if (DEBUG) {
- Log.d(TAG, "calling native_inject_xtra_data");
- }
- native_inject_xtra_data(data, data.length);
- } else {
- // try again later
- // since this is delayed and not urgent we do not hold a wake lock here
- mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
- mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA),
- RETRY_INTERVAL);
+ if (!mNetworkAvailable) {
+ // try again when network is up
+ mDownloadXtraDataPending = STATE_PENDING_NETWORK;
+ return;
}
+ mDownloadXtraDataPending = STATE_DOWNLOADING;
+
+ // hold wake lock while task runs
+ mWakeLock.acquire();
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
+ byte[] data = xtraDownloader.downloadXtraData();
+ if (data != null) {
+ if (DEBUG) {
+ Log.d(TAG, "calling native_inject_xtra_data");
+ }
+ native_inject_xtra_data(data, data.length);
+ }
+
+ sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
+
+ if (data == null) {
+ // try again later
+ // since this is delayed and not urgent we do not hold a wake lock here
+ mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL);
+ }
+
+ // release wake lock held by task
+ mWakeLock.release();
+ }
+ });
}
private void handleUpdateLocation(Location location) {
@@ -1442,11 +1481,17 @@
private void sendMessage(int message, int arg, Object obj) {
// hold a wake lock until this message is delivered
+ // note that this assumes the message will not be removed from the queue before
+ // it is handled (otherwise the wake lock would be leaked).
mWakeLock.acquire();
mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
}
private final class ProviderHandler extends Handler {
+ public ProviderHandler() {
+ super(true /*async*/);
+ }
+
@Override
public void handleMessage(Message msg) {
int message = msg.what;
@@ -1473,6 +1518,12 @@
handleDownloadXtraData();
}
break;
+ case INJECT_NTP_TIME_FINISHED:
+ mInjectNtpTimePending = STATE_IDLE;
+ break;
+ case DOWNLOAD_XTRA_DATA_FINISHED:
+ mDownloadXtraDataPending = STATE_IDLE;
+ break;
case UPDATE_LOCATION:
handleUpdateLocation((Location)msg.obj);
break;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index a76f854..0345df1 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -64,11 +64,12 @@
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.UserInfo;
+import android.content.pm.PackageUserState;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageStats;
import android.content.pm.ParceledListSlice;
@@ -103,7 +104,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings.Secure;
import android.security.SystemKeyStore;
import android.util.DisplayMetrics;
@@ -168,6 +168,7 @@
static final boolean DEBUG_UPGRADE = false;
private static final boolean DEBUG_INSTALL = false;
private static final boolean DEBUG_REMOVE = false;
+ private static final boolean DEBUG_BROADCASTS = false;
private static final boolean DEBUG_SHOW_INFO = false;
private static final boolean DEBUG_PACKAGE_INFO = false;
private static final boolean DEBUG_INTENT_MATCHING = false;
@@ -400,6 +401,7 @@
// package uri's from external media onto secure containers
// or internal storage.
private IMediaContainerService mContainerService = null;
+ private int mContainerServiceUserId;
static final int SEND_PENDING_BROADCAST = 1;
static final int MCS_BOUND = 3;
@@ -468,8 +470,12 @@
" DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ mContainerServiceUserId = 0;
+ if (mPendingInstalls.size() > 0) {
+ mContainerServiceUserId = mPendingInstalls.get(0).getUser().getIdentifier();
+ }
if (mContext.bindService(service, mDefContainerConn,
- Context.BIND_AUTO_CREATE)) {
+ Context.BIND_AUTO_CREATE, mContainerServiceUserId)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
@@ -546,6 +552,12 @@
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
+ // Check if we're connected to the correct service, if it's an install
+ // request.
+ if (params.getUser().getIdentifier() != mContainerServiceUserId) {
+ mHandler.sendEmptyMessage(MCS_RECONNECT);
+ return;
+ }
if (params.startCopy()) {
// We are done... look for more work or to
// go idle.
@@ -662,15 +674,21 @@
break;
}
case START_CLEANING_PACKAGE: {
- String packageName = (String)msg.obj;
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ PackageCleanItem item = new PackageCleanItem((String)msg.obj,
+ msg.arg2 != 0);
synchronized (mPackages) {
- if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {
- mSettings.mPackagesToBeCleaned.add(packageName);
+ if (msg.arg1 == UserHandle.USER_ALL) {
+ int[] users = sUserManager.getUserIds();
+ for (int user : users) {
+ mSettings.addPackageToCleanLPw(user, item);
+ }
+ } else {
+ mSettings.addPackageToCleanLPw(msg.arg1, item);
}
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- startCleaningPackages();
+ startCleaningPackages(-1);
} break;
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
@@ -692,15 +710,14 @@
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, res.users);
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
res.pkg.applicationInfo.packageName,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, res.users);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null, null,
- res.pkg.applicationInfo.packageName, null,
- UserHandle.USER_ALL);
+ res.pkg.applicationInfo.packageName, null, res.users);
}
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
@@ -780,7 +797,7 @@
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
- if (state != null) {
+ if ((state != null) && !state.timeoutExtended()) {
final InstallArgs args = state.getInstallArgs();
Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());
mPendingVerification.remove(verificationId);
@@ -788,20 +805,20 @@
int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
- Slog.i(TAG, "Continuing with installation of " + args.packageURI.toString());
- state.setVerifierResponse(Binder.getCallingUid(), PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
- try {
- ret = args.copyApk(mContainerService, true);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not contact the ContainerService");
- }
+ Slog.i(TAG, "Continuing with installation of "
+ + args.packageURI.toString());
+ state.setVerifierResponse(Binder.getCallingUid(),
+ PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
+ try {
+ ret = args.copyApk(mContainerService, true);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not contact the ContainerService");
+ }
}
processPendingInstall(args, ret);
-
mHandler.sendEmptyMessage(MCS_UNBIND);
}
-
break;
}
case PACKAGE_VERIFIED: {
@@ -944,8 +961,8 @@
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
- sUserManager = UserManagerService.getInstance(context);
- sUserManager.setInstaller(this, mInstaller);
+ sUserManager = new UserManagerService(context, this,
+ mInstallLock, mPackages);
readPermissions();
@@ -1139,8 +1156,7 @@
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
- mInstaller.remove(ps.name, 0);
- sUserManager.removePackageForAllUsers(ps.name);
+ removeDataDirsLI(ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
@@ -1189,9 +1205,7 @@
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
-
- mInstaller.remove(deletedAppName, 0);
- sUserManager.removePackageForAllUsers(deletedAppName);
+ removeDataDirsLI(deletedAppName);
} else {
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
@@ -1326,13 +1340,7 @@
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
- int retCode = mInstaller.remove(ps.name, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data directory for package: "
- + ps.name + ", retcode=" + retCode);
- } else {
- sUserManager.removePackageForAllUsers(ps.name);
- }
+ removeDataDirsLI(ps.name);
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
Slog.w(TAG, "Unable to remove old code file: " + ps.codePath);
@@ -1562,19 +1570,17 @@
PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
PackageInfo pi;
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- // The package has been uninstalled but has retained data and resources.
- pi = PackageParser.generatePackageInfo(p, null, flags, 0, 0, null, false, 0, userId);
- } else {
- final PackageSetting ps = (PackageSetting) p.mExtras;
- if (ps == null) {
- return null;
- }
- final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
- pi = PackageParser.generatePackageInfo(p, gp.gids, flags,
- ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
- ps.getStopped(userId), ps.getEnabled(userId), userId);
- pi.applicationInfo.enabledSetting = ps.getEnabled(userId);
+ final PackageSetting ps = (PackageSetting) p.mExtras;
+ if (ps == null) {
+ return null;
+ }
+ final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+ final PackageUserState state = ps.readUserState(userId);
+ pi = PackageParser.generatePackageInfo(p, gp.gids, flags,
+ ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
+ state, userId);
+ if (pi != null) {
+ pi.applicationInfo.enabledSetting = state.enabled;
pi.applicationInfo.enabled =
pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT
|| pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
@@ -1741,14 +1747,15 @@
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
if (ps.pkg == null) {
- PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags, userId);
+ PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName,
+ flags, userId);
if (pInfo != null) {
return pInfo.applicationInfo;
}
return null;
}
- return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId),
- ps.getEnabled(userId), userId);
+ return PackageParser.generateApplicationInfo(ps.pkg, flags,
+ ps.readUserState(userId), userId);
}
return null;
}
@@ -1758,20 +1765,23 @@
if (!sUserManager.exists(userId)) return null;
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
- PackageParser.Package pkg = new PackageParser.Package(packageName);
- if (ps.pkg == null) {
- ps.pkg = new PackageParser.Package(packageName);
- ps.pkg.applicationInfo.packageName = packageName;
- ps.pkg.applicationInfo.flags = ps.pkgFlags;
- ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
- ps.pkg.applicationInfo.sourceDir = ps.codePathString;
- ps.pkg.applicationInfo.dataDir =
+ PackageParser.Package pkg = ps.pkg;
+ if (pkg == null) {
+ if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
+ return null;
+ }
+ pkg = new PackageParser.Package(packageName);
+ pkg.applicationInfo.packageName = packageName;
+ pkg.applicationInfo.flags = ps.pkgFlags;
+ pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
+ pkg.applicationInfo.sourceDir = ps.codePathString;
+ pkg.applicationInfo.dataDir =
getDataPathForPackage(ps.pkg.packageName, 0).getPath();
- ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
+ pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
}
- // ps.pkg.mSetEnabled = ps.getEnabled(userId);
- // ps.pkg.mSetStopped = ps.getStopped(userId);
- return generatePackageInfo(ps.pkg, flags, userId);
+ // pkg.mSetEnabled = ps.getEnabled(userId);
+ // pkg.mSetStopped = ps.getStopped(userId);
+ return generatePackageInfo(pkg, flags, userId);
}
return null;
}
@@ -1789,13 +1799,12 @@
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) return null;
// Note: isEnabledLP() does not apply here - always return info
- return PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
- ps.getEnabled(userId));
+ return PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId));
}
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
}
- if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
}
}
@@ -1811,9 +1820,11 @@
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
+ synchronized (mInstallLock) {
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
}
if (observer != null) {
try {
@@ -1834,9 +1845,11 @@
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
+ synchronized (mInstallLock) {
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
}
if(pi != null) {
try {
@@ -1862,8 +1875,8 @@
if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId),
- ps.getEnabled(userId), userId);
+ return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
+ userId);
}
if (mResolveComponentName.equals(component)) {
return mResolveActivity;
@@ -1882,8 +1895,8 @@
if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId),
- ps.getEnabled(userId), userId);
+ return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
+ userId);
}
}
return null;
@@ -1899,8 +1912,8 @@
if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- return PackageParser.generateServiceInfo(s, flags, ps.getStopped(userId),
- ps.getEnabled(userId), userId);
+ return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
+ userId);
}
}
return null;
@@ -1916,8 +1929,8 @@
if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- return PackageParser.generateProviderInfo(p, flags, ps.getStopped(userId),
- ps.getEnabled(userId), userId);
+ return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId),
+ userId);
}
}
return null;
@@ -2870,8 +2883,8 @@
} else {
final PackageParser.Package p = mPackages.get(packageName);
if (p != null && ps != null) {
- ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
- ps.getEnabled(userId), userId);
+ ai = PackageParser.generateApplicationInfo(p, flags,
+ ps.readUserState(userId), userId);
}
}
@@ -2901,10 +2914,13 @@
&& (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
&& (!mSafeMode || isSystemApp(p))) {
PackageSetting ps = mSettings.mPackages.get(p.packageName);
- finalList.add(PackageParser.generateApplicationInfo(p, flags,
- ps != null ? ps.getStopped(userId) : false,
- ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
- userId));
+ if (ps != null) {
+ ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+ ps.readUserState(userId), userId);
+ if (ai != null) {
+ finalList.add(ai);
+ }
+ }
}
}
}
@@ -2921,14 +2937,12 @@
PackageSetting ps = provider != null
? mSettings.mPackages.get(provider.owner.packageName)
: null;
- return provider != null
+ return ps != null
&& mSettings.isEnabledLPr(provider.info, flags, userId)
&& (!mSafeMode || (provider.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)
? PackageParser.generateProviderInfo(provider, flags,
- ps != null ? ps.getStopped(userId) : false,
- ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
- userId)
+ ps.readUserState(userId), userId)
: null;
}
}
@@ -2948,14 +2962,15 @@
PackageParser.Provider p = entry.getValue();
PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
- if (p.syncable
+ if (ps != null && p.syncable
&& (!mSafeMode || (p.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)) {
- outNames.add(entry.getKey());
- outInfo.add(PackageParser.generateProviderInfo(p, 0,
- ps != null ? ps.getStopped(userId) : false,
- ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
- userId));
+ ProviderInfo info = PackageParser.generateProviderInfo(p, 0,
+ ps.readUserState(userId), userId);
+ if (info != null) {
+ outNames.add(entry.getKey());
+ outInfo.add(info);
+ }
}
}
}
@@ -2973,7 +2988,7 @@
while (i.hasNext()) {
final PackageParser.Provider p = i.next();
PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
- if (p.info.authority != null
+ if (ps != null && p.info.authority != null
&& (processName == null
|| (p.info.processName.equals(processName)
&& UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
@@ -2983,10 +2998,11 @@
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
- finalList.add(PackageParser.generateProviderInfo(p, flags,
- ps != null ? ps.getStopped(userId) : false,
- ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
- userId));
+ ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
+ ps.readUserState(userId), userId);
+ if (info != null) {
+ finalList.add(info);
+ }
}
}
}
@@ -3019,8 +3035,11 @@
final PackageParser.Instrumentation p = i.next();
if (targetPackage == null
|| targetPackage.equals(p.info.targetPackage)) {
- finalList.add(PackageParser.generateInstrumentationInfo(p,
- flags));
+ InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p,
+ flags);
+ if (ii != null) {
+ finalList.add(ii);
+ }
}
}
}
@@ -3047,7 +3066,7 @@
continue;
}
PackageParser.Package pkg = scanPackageLI(file,
- flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
+ flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
// Don't mess around with apps in system partition.
if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
@@ -3115,7 +3134,7 @@
* Returns null in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile,
- int parseFlags, int scanMode, long currentTime) {
+ int parseFlags, int scanMode, long currentTime, UserHandle user) {
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
String scanPath = scanFile.getPath();
parseFlags |= mDefParseFlags;
@@ -3181,7 +3200,7 @@
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
- synchronized (mInstaller) {
+ synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
synchronized (mPackages) {
@@ -3215,7 +3234,7 @@
*/
if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
- deletePackageLI(pkg.packageName, true, 0, null, false);
+ deletePackageLI(pkg.packageName, null, true, 0, null, false);
ps = null;
} else {
/*
@@ -3237,7 +3256,7 @@
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
- synchronized (mInstaller) {
+ synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
@@ -3268,7 +3287,7 @@
setApplicationInfoPaths(pkg, codePath, resPath);
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
- | SCAN_UPDATE_SIGNATURE, currentTime);
+ | SCAN_UPDATE_SIGNATURE, currentTime, user);
/*
* If the system app should be overridden by a previously installed
@@ -3471,8 +3490,38 @@
}
}
+ private int createDataDirsLI(String packageName, int uid) {
+ int[] users = sUserManager.getUserIds();
+ int res = mInstaller.install(packageName, uid, uid);
+ if (res < 0) {
+ return res;
+ }
+ for (int user : users) {
+ if (user != 0) {
+ res = mInstaller.createUserData(packageName,
+ UserHandle.getUid(user, uid), user);
+ if (res < 0) {
+ return res;
+ }
+ }
+ }
+ return res;
+ }
+
+ private int removeDataDirsLI(String packageName) {
+ int[] users = sUserManager.getUserIds();
+ int res = 0;
+ for (int user : users) {
+ int resInner = mInstaller.remove(packageName, user);
+ if (resInner < 0) {
+ res = resInner;
+ }
+ }
+ return res;
+ }
+
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
- int parseFlags, int scanMode, long currentTime) {
+ int parseFlags, int scanMode, long currentTime, UserHandle user) {
File scanFile = new File(pkg.mScanPath);
if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
pkg.applicationInfo.publicSourceDir == null) {
@@ -3664,7 +3713,7 @@
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
- pkg.applicationInfo.flags, true, false);
+ pkg.applicationInfo.flags, user, false);
if (pkgSetting == null) {
Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -3823,11 +3872,9 @@
|| (scanMode&SCAN_BOOTING) != 0)) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
- int ret = mInstaller.remove(pkgName, 0);
+ int ret = removeDataDirsLI(pkgName);
if (ret >= 0) {
// TODO: Kill the processes first
- // Remove the data directories for all users
- sUserManager.removePackageForAllUsers(pkgName);
// Old data gone!
String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
? "System package " : "Third party package ";
@@ -3839,8 +3886,7 @@
recovered = true;
// And now re-install the app.
- ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
+ ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
if (ret == -1) {
// Ack should not happen!
msg = prefix + pkg.packageName
@@ -3849,9 +3895,6 @@
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- // Create data directories for all users
- sUserManager.installPackageForAllUsers(pkgName,
- pkg.applicationInfo.uid);
}
if (!recovered) {
mHasSystemUidErrors = true;
@@ -3889,15 +3932,12 @@
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
- int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
+ int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
if (ret < 0) {
// Error from installer
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- // Create data directories for all users
- sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
@@ -4024,7 +4064,9 @@
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
- mSettings.mPackagesToBeCleaned.remove(pkgName);
+ for (int i=0; i<mSettings.mPackagesToBeCleaned.size(); i++) {
+ mSettings.mPackagesToBeCleaned.valueAt(i).remove(pkgName);
+ }
// Take care of first install / last update times.
if (currentTime != 0) {
@@ -4840,7 +4882,8 @@
// System apps are never considered stopped for purposes of
// filtering, because there may be no way for the user to
// actually re-launch them.
- return ps.getStopped(userId) && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0;
+ return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
+ && ps.getStopped(userId);
}
}
return false;
@@ -4863,12 +4906,17 @@
&ApplicationInfo.FLAG_SYSTEM) == 0) {
return null;
}
- final ResolveInfo res = new ResolveInfo();
PackageSetting ps = (PackageSetting) activity.owner.mExtras;
- res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags,
- ps != null ? ps.getStopped(userId) : false,
- ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
- userId);
+ if (ps == null) {
+ return null;
+ }
+ ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags,
+ ps.readUserState(userId), userId);
+ if (ai == null) {
+ return null;
+ }
+ final ResolveInfo res = new ResolveInfo();
+ res.activityInfo = ai;
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = info;
}
@@ -5031,8 +5079,8 @@
// System apps are never considered stopped for purposes of
// filtering, because there may be no way for the user to
// actually re-launch them.
- return ps.getStopped(userId)
- && (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0;
+ return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+ && ps.getStopped(userId);
}
}
return false;
@@ -5056,12 +5104,17 @@
&ApplicationInfo.FLAG_SYSTEM) == 0) {
return null;
}
- final ResolveInfo res = new ResolveInfo();
PackageSetting ps = (PackageSetting) service.owner.mExtras;
- res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags,
- ps != null ? ps.getStopped(userId) : false,
- ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
- userId);
+ if (ps == null) {
+ return null;
+ }
+ ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
+ ps.readUserState(userId), userId);
+ if (si == null) {
+ return null;
+ }
+ final ResolveInfo res = new ResolveInfo();
+ res.serviceInfo = si;
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = filter;
}
@@ -5152,13 +5205,14 @@
};
static final void sendPackageBroadcast(String action, String pkg,
- Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) {
+ Bundle extras, String targetPkg, IIntentReceiver finishedReceiver,
+ int[] userIds) {
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
- int[] userIds = userId == UserHandle.USER_ALL
- ? sUserManager.getUserIds()
- : new int[] {userId};
+ if (userIds == null) {
+ userIds = sUserManager.getUserIds();
+ }
for (int id : userIds) {
final Intent intent = new Intent(action,
pkg != null ? Uri.fromParts("package", pkg, null) : null);
@@ -5170,11 +5224,18 @@
}
// Modify the UID when posting to other users
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (uid > 0 && id > 0) {
+ if (uid > 0 && UserHandle.getUserId(uid) != id) {
uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
intent.putExtra(Intent.EXTRA_UID, uid);
}
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ if (DEBUG_BROADCASTS) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "Sending to user " + id + ": "
+ + intent.toShortString(false, true, false, false)
+ + " " + intent.getExtras(), here);
+ }
am.broadcastIntent(null, intent, null, finishedReceiver,
0, null, null, null, finishedReceiver != null, false, id);
}
@@ -5192,8 +5253,9 @@
return mMediaMounted || Environment.isExternalStorageEmulated();
}
- public String nextPackageToClean(String lastPackage) {
+ public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
// writer
+ final int userId = UserHandle.getCallingUserId();
synchronized (mPackages) {
if (!isExternalMediaAvailable()) {
// If the external storage is no longer mounted at this point,
@@ -5201,34 +5263,65 @@
// packages files and can not delete any more. Bail.
return null;
}
- if (lastPackage != null) {
- mSettings.mPackagesToBeCleaned.remove(lastPackage);
+ ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned.get(userId);
+ if (pkgs != null) {
+ if (lastPackage != null) {
+ pkgs.remove(lastPackage);
+ }
+ if (pkgs.size() > 0) {
+ return pkgs.get(0);
+ }
}
- return mSettings.mPackagesToBeCleaned.size() > 0
- ? mSettings.mPackagesToBeCleaned.get(0) : null;
}
+ // Move on to the next user to clean.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ startCleaningPackages(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return null;
}
- void schedulePackageCleaning(String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, packageName));
+ void schedulePackageCleaning(String packageName, int userId, boolean andCode) {
+ if (false) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "Schedule cleaning " + packageName + " user=" + userId
+ + " andCode=" + andCode, here);
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE,
+ userId, andCode ? 1 : 0, packageName));
}
- void startCleaningPackages() {
+ void startCleaningPackages(int lastUser) {
// reader
+ int nextUser = -1;
synchronized (mPackages) {
if (!isExternalMediaAvailable()) {
return;
}
- if (mSettings.mPackagesToBeCleaned.size() <= 0) {
+ final int N = mSettings.mPackagesToBeCleaned.size();
+ if (N <= 0) {
return;
}
+ for (int i=0; i<N; i++) {
+ int user = mSettings.mPackagesToBeCleaned.keyAt(i);
+ if (user > lastUser) {
+ nextUser = user;
+ break;
+ }
+ }
+ if (nextUser < 0) {
+ nextUser = mSettings.mPackagesToBeCleaned.keyAt(0);
+ }
}
Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE);
intent.setComponent(DEFAULT_CONTAINER_COMPONENT);
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
- am.startService(null, intent, null);
+ am.startService(null, intent, null, nextUser);
} catch (RemoteException e) {
}
}
@@ -5291,7 +5384,7 @@
PackageParser.PARSE_CHATTY |
PackageParser.PARSE_MUST_BE_APK,
SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
- System.currentTimeMillis());
+ System.currentTimeMillis(), null);
if (p != null) {
/*
* TODO this seems dangerous as the package may have
@@ -5320,13 +5413,13 @@
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, null);
}
if (addedPackage != null) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, addedUid);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, null);
}
}
@@ -5365,6 +5458,12 @@
null);
final int uid = Binder.getCallingUid();
+ UserHandle user;
+ if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
+ user = UserHandle.ALL;
+ } else {
+ user = Process.myUserHandle();
+ }
final int filteredFlags;
@@ -5379,10 +5478,51 @@
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
- verificationParams, encryptionParams);
+ verificationParams, encryptionParams, user);
mHandler.sendMessage(msg);
}
+ /**
+ * @hide
+ */
+ @Override
+ public int installExistingPackage(String packageName) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
+ null);
+ PackageSetting pkgSetting;
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ boolean sendAdded = false;
+ Bundle extras = new Bundle(1);
+
+ // writer
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null) {
+ return PackageManager.INSTALL_FAILED_INVALID_URI;
+ }
+ if (!pkgSetting.getInstalled(userId)) {
+ pkgSetting.setInstalled(true, userId);
+ mSettings.writePackageRestrictionsLPr(userId);
+ extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
+ sendAdded = true;
+ }
+ }
+
+ if (sendAdded) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ packageName, extras, null, null, new int[] {userId});
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
@Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
@@ -5393,6 +5533,32 @@
mHandler.sendMessage(msg);
}
+ @Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ final PackageVerificationState state = mPendingVerification.get(id);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCodeAtTimeout, Binder.getCallingUid());
+
+ if ((millisecondsToDelay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT)
+ || (millisecondsToDelay < 0)) {
+ throw new IllegalArgumentException("millisecondsToDelay is out of bounds.");
+ }
+ if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW)
+ || (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) {
+ throw new IllegalArgumentException("verificationCodeAtTimeout is unknown.");
+ }
+
+ if ((state != null) && !state.timeoutExtended()) {
+ state.extendTimeout();
+
+ final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessageDelayed(msg, millisecondsToDelay);
+ }
+ }
+
private ComponentName matchComponentForVerifier(String packageName,
List<ResolveInfo> receivers) {
ActivityInfo targetReceiver = null;
@@ -5695,6 +5861,17 @@
*/
private int mRetries = 0;
+ /** User handle for the user requesting the information or installation. */
+ private final UserHandle mUser;
+
+ HandlerParams(UserHandle user) {
+ mUser = user;
+ }
+
+ UserHandle getUser() {
+ return mUser;
+ }
+
final boolean startCopy() {
boolean res;
try {
@@ -5736,6 +5913,7 @@
private final IPackageStatsObserver mObserver;
public MeasureParams(PackageStats stats, IPackageStatsObserver observer) {
+ super(new UserHandle(stats.userHandle));
mObserver = observer;
mStats = stats;
}
@@ -5818,7 +5996,8 @@
InstallParams(Uri packageURI,
IPackageInstallObserver observer, int flags,
String installerPackageName, VerificationParams verificationParams,
- ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams, UserHandle user) {
+ super(user);
this.mPackageURI = packageURI;
this.flags = flags;
this.observer = observer;
@@ -5843,6 +6022,16 @@
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg != null) {
if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ // Check for downgrading.
+ if ((flags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) {
+ if (pkgLite.versionCode < pkg.mVersionCode) {
+ Slog.w(TAG, "Can't install update of " + packageName
+ + " update version " + pkgLite.versionCode
+ + " is older than installed version "
+ + pkg.mVersionCode);
+ return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
+ }
+ }
// Check for updated system application.
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
if (onSd) {
@@ -5969,6 +6158,8 @@
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
+ ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else {
// Override with defaults if needed.
loc = installLocationPolicy(pkgLite, flags);
@@ -6159,7 +6350,8 @@
int mRet;
MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags,
- String packageName, String dataDir, int uid) {
+ String packageName, String dataDir, int uid, UserHandle user) {
+ super(user);
this.srcArgs = srcArgs;
this.observer = observer;
this.flags = flags;
@@ -6312,14 +6504,17 @@
final Uri packageURI;
final String installerPackageName;
final ManifestDigest manifestDigest;
+ final UserHandle user;
InstallArgs(Uri packageURI, IPackageInstallObserver observer, int flags,
- String installerPackageName, ManifestDigest manifestDigest) {
+ String installerPackageName, ManifestDigest manifestDigest,
+ UserHandle user) {
this.packageURI = packageURI;
this.flags = flags;
this.observer = observer;
this.installerPackageName = installerPackageName;
this.manifestDigest = manifestDigest;
+ this.user = user;
}
abstract void createCopyFile();
@@ -6370,11 +6565,12 @@
FileInstallArgs(InstallParams params) {
super(params.getPackageUri(), params.observer, params.flags,
- params.installerPackageName, params.getManifestDigest());
+ params.installerPackageName, params.getManifestDigest(),
+ params.getUser());
}
FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) {
- super(null, null, 0, null, null);
+ super(null, null, 0, null, null, null);
File codeFile = new File(fullCodePath);
installDir = codeFile.getParentFile();
codeFileName = fullCodePath;
@@ -6383,7 +6579,7 @@
}
FileInstallArgs(Uri packageURI, String pkgName, String dataDir) {
- super(packageURI, null, 0, null, null);
+ super(packageURI, null, 0, null, null, null);
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
String apkName = getNextCodePath(null, pkgName, ".apk");
codeFileName = new File(installDir, apkName + ".apk").getPath();
@@ -6657,13 +6853,15 @@
AsecInstallArgs(InstallParams params) {
super(params.getPackageUri(), params.observer, params.flags,
- params.installerPackageName, params.getManifestDigest());
+ params.installerPackageName, params.getManifestDigest(),
+ params.getUser());
}
AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
boolean isExternal, boolean isForwardLocked) {
super(null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null);
+ | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
+ null, null, null);
// Extract cid from fullCodePath
int eidx = fullCodePath.lastIndexOf("/");
String subStr1 = fullCodePath.substring(0, eidx);
@@ -6674,14 +6872,16 @@
AsecInstallArgs(String cid, boolean isForwardLocked) {
super(null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null);
+ | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
+ null, null, null);
this.cid = cid;
setCachePath(PackageHelper.getSdDir(cid));
}
AsecInstallArgs(Uri packageURI, String cid, boolean isExternal, boolean isForwardLocked) {
super(packageURI, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), null, null);
+ | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
+ null, null, null);
this.cid = cid;
}
@@ -7005,6 +7205,7 @@
class PackageInstalledInfo {
String name;
int uid;
+ int[] users;
PackageParser.Package pkg;
int returnCode;
PackageRemovedInfo removedInfo;
@@ -7014,14 +7215,12 @@
* Install a non-existing package.
*/
private void installNewPackageLI(PackageParser.Package pkg,
- int parseFlags,
- int scanMode,
+ int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
- res.name = pkgName;
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
@@ -7044,7 +7243,7 @@
}
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
- System.currentTimeMillis());
+ System.currentTimeMillis(), user);
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -7061,17 +7260,15 @@
// delete the package data and cache directories that it created in
// scanPackageLocked, unless those directories existed before we even tried to
// install.
- deletePackageLI(
- pkgName, false,
- dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
+ deletePackageLI(pkgName, UserHandle.ALL, false,
+ dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
res.removedInfo, true);
}
}
}
private void replacePackageLI(PackageParser.Package pkg,
- int parseFlags,
- int scanMode,
+ int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package oldPackage;
@@ -7088,15 +7285,16 @@
}
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
- replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
+ replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
+ user, installerPackageName, res);
} else {
- replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
+ replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
+ user, installerPackageName, res);
}
}
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
- PackageParser.Package pkg,
- int parseFlags, int scanMode,
+ PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
String pkgName = deletedPackage.packageName;
@@ -7111,7 +7309,7 @@
}
// First delete the existing package while retaining the data directory
- if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
+ if (!deletePackageLI(pkgName, null, true, PackageManager.DELETE_KEEP_DATA,
res.removedInfo, true)) {
// If the existing package wasn't successfully deleted
res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
@@ -7120,7 +7318,7 @@
// Successfully deleted the old package. Now proceed with re-installation
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
- System.currentTimeMillis());
+ System.currentTimeMillis(), user);
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -7141,8 +7339,8 @@
// install.
if(updatedSettings) {
deletePackageLI(
- pkgName, true,
- PackageManager.DONT_DELETE_DATA,
+ pkgName, null, true,
+ PackageManager.DELETE_KEEP_DATA,
res.removedInfo, true);
}
// Since we failed to install the new package we need to restore the old
@@ -7157,7 +7355,7 @@
int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE
| SCAN_UPDATE_TIME;
if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode,
- origUpdateTime) == null) {
+ origUpdateTime, user) == null) {
Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
return;
}
@@ -7175,8 +7373,7 @@
}
private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
- PackageParser.Package pkg,
- int parseFlags, int scanMode,
+ PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
boolean updatedSettings = false;
@@ -7225,7 +7422,7 @@
// Successfully disabled the old package. Now proceed with re-installation
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0);
+ newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user);
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -7248,7 +7445,7 @@
removePackageLI(newPackage, true);
}
// Add back the old system package
- scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0);
+ scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user);
// Restore the old system information in Settings
synchronized(mPackages) {
if (updatedSettings) {
@@ -7307,6 +7504,10 @@
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
? UPDATE_PERMISSIONS_ALL : 0));
res.name = pkgName;
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ res.users = ps.getInstalledUsers(sUserManager.getUserIds());
+ }
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
@@ -7422,12 +7623,18 @@
setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
- replacePackageLI(pkg, parseFlags, scanMode,
+ replacePackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
} else {
- installNewPackageLI(pkg, parseFlags, scanMode,
+ installNewPackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName,res);
}
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ res.users = ps.getInstalledUsers(sUserManager.getUserIds());
+ }
+ }
}
private static boolean isForwardLocked(PackageParser.Package pkg) {
@@ -7518,10 +7725,11 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
// Queue up an async operation since the package deletion may take a little while.
+ final int uid = Binder.getCallingUid();
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- final int returnCode = deletePackageX(packageName, true, true, flags);
+ final int returnCode = deletePackageX(packageName, uid, flags);
if (observer != null) {
try {
observer.packageDeleted(packageName, returnCode);
@@ -7547,8 +7755,7 @@
* persisting settings for later use
* sending a broadcast if necessary
*/
- private int deletePackageX(String packageName, boolean sendBroadCast,
- boolean deleteCodeAndResources, int flags) {
+ private int deletePackageX(String packageName, int uid, int flags) {
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
@@ -7563,27 +7770,30 @@
}
synchronized (mInstallLock) {
- res = deletePackageLI(packageName, deleteCodeAndResources,
- flags | REMOVE_CHATTY, info, true);
+ res = deletePackageLI(packageName,
+ (flags & PackageManager.DELETE_ALL_USERS) != 0
+ ? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)),
+ true, flags | REMOVE_CHATTY, info, true);
}
- if (res && sendBroadCast) {
+ if (res) {
boolean systemUpdate = info.isRemovedPackageSystemUpdate;
- info.sendBroadcast(deleteCodeAndResources, systemUpdate);
+ info.sendBroadcast(true, systemUpdate);
// If the removed package was a system update, the old system packaged
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
+ extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
+ ? info.removedAppId : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
- null, packageName, null, UserHandle.USER_ALL);
+ null, packageName, null, null);
}
}
// Force a gc here.
@@ -7592,7 +7802,7 @@
// other processes clean up before deleting resources.
if (info.args != null) {
synchronized (mInstallLock) {
- info.args.doPostDeleteLI(deleteCodeAndResources);
+ info.args.doPostDeleteLI(true);
}
}
@@ -7602,29 +7812,30 @@
static class PackageRemovedInfo {
String removedPackage;
int uid = -1;
- int removedUid = -1;
+ int removedAppId = -1;
+ int[] removedUsers = null;
boolean isRemovedPackageSystemUpdate = false;
// Clean up resources deleted packages.
InstallArgs args = null;
void sendBroadcast(boolean fullRemove, boolean replacing) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
+ extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
if (replacing) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
if (removedPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, removedUsers);
if (fullRemove && !replacing) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
- extras, null, null, UserHandle.USER_ALL);
+ extras, null, null, removedUsers);
}
}
- if (removedUid >= 0) {
+ if (removedAppId >= 0) {
sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
- UserHandle.getUserId(removedUid));
+ removedUsers);
}
}
}
@@ -7638,34 +7849,28 @@
private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
int flags, boolean writeSettings) {
String packageName = p.packageName;
- if (outInfo != null) {
- outInfo.removedPackage = packageName;
- }
removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
// reader
synchronized (mPackages) {
deletedPs = mSettings.mPackages.get(packageName);
- }
- if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- int retCode = mInstaller.remove(packageName, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
- + packageName + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- } else {
- // TODO: Kill the processes first
- sUserManager.removePackageForAllUsers(packageName);
+ if (outInfo != null) {
+ outInfo.removedPackage = packageName;
+ outInfo.removedUsers = deletedPs != null
+ ? deletedPs.getInstalledUsers(sUserManager.getUserIds()) : null;
}
- schedulePackageCleaning(packageName);
+ }
+ if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
+ removeDataDirsLI(packageName);
+ schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
// writer
synchronized (mPackages) {
if (deletedPs != null) {
- if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
+ if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
if (outInfo != null) {
- outInfo.removedUid = mSettings.removePackageLPw(packageName);
+ outInfo.removedAppId = mSettings.removePackageLPw(packageName);
}
if (deletedPs != null) {
updatePermissionsLPw(deletedPs.name, null, 0);
@@ -7714,10 +7919,10 @@
outInfo.isRemovedPackageSystemUpdate = true;
if (ps.versionCode < p.mVersionCode) {
// Delete data for downgrades
- flags &= ~PackageManager.DONT_DELETE_DATA;
+ flags &= ~PackageManager.DELETE_KEEP_DATA;
} else {
// Preserve data by setting flag
- flags |= PackageManager.DONT_DELETE_DATA;
+ flags |= PackageManager.DELETE_KEEP_DATA;
}
boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo,
writeSettings);
@@ -7734,7 +7939,7 @@
// Install the system package
PackageParser.Package newPkg = scanPackageLI(ps.codePath,
PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
- SCAN_MONITOR | SCAN_NO_PATHS, 0);
+ SCAN_MONITOR | SCAN_NO_PATHS, 0, null);
if (newPkg == null) {
Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
@@ -7781,7 +7986,7 @@
/*
* This method handles package deletion in general
*/
- private boolean deletePackageLI(String packageName,
+ private boolean deletePackageLI(String packageName, UserHandle user,
boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo,
boolean writeSettings) {
if (packageName == null) {
@@ -7790,6 +7995,8 @@
}
PackageParser.Package p;
boolean dataOnly = false;
+ int removeUser = -1;
+ int appId = -1;
synchronized (mPackages) {
p = mPackages.get(packageName);
if (p == null) {
@@ -7797,15 +8004,53 @@
dataOnly = true;
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) {
- Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
}
p = ps.pkg;
}
+ if (p == null) {
+ Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
+ return false;
+ }
+ final PackageSetting ps = (PackageSetting)p.mExtras;
+ if (!isSystemApp(p) && ps != null && user != null
+ && user.getIdentifier() != UserHandle.USER_ALL) {
+ // The caller is asking that the package only be deleted for a single
+ // user. To do this, we just mark its uninstalled state and delete
+ // its data.
+ ps.setUserState(user.getIdentifier(),
+ COMPONENT_ENABLED_STATE_DEFAULT,
+ false, //installed
+ true, //stopped
+ true, //notLaunched
+ null, null);
+ if (ps.isAnyInstalled(sUserManager.getUserIds())) {
+ // Other user still have this package installed, so all
+ // we need to do is clear this user's data and save that
+ // it is uninstalled.
+ removeUser = user.getIdentifier();
+ appId = ps.appId;
+ mSettings.writePackageRestrictionsLPr(removeUser);
+ } else {
+ // We need to set it back to 'installed' so the uninstall
+ // broadcasts will be sent correctly.
+ ps.setInstalled(true, user.getIdentifier());
+ }
+ }
}
- if (p == null) {
- Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
- return false;
+
+ if (removeUser >= 0) {
+ // From above, we determined that we are deleting this only
+ // for a single user. Continue the work here.
+ if (outInfo != null) {
+ outInfo.removedPackage = packageName;
+ outInfo.removedAppId = appId;
+ outInfo.removedUsers = new int[] {removeUser};
+ }
+ mInstaller.clearUserData(packageName, removeUser);
+ schedulePackageCleaning(packageName, removeUser, false);
+ return true;
}
if (dataOnly) {
@@ -7850,7 +8095,7 @@
}
}
- private void clearExternalStorageDataSync(String packageName, boolean allData) {
+ private void clearExternalStorageDataSync(String packageName, int userId, boolean allData) {
final boolean mounted;
if (Environment.isExternalStorageEmulated()) {
mounted = true;
@@ -7866,44 +8111,52 @@
}
final Intent containerIntent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- ClearStorageConnection conn = new ClearStorageConnection();
- if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE)) {
- try {
- long timeout = SystemClock.uptimeMillis() + 5000;
- synchronized (conn) {
- long now = SystemClock.uptimeMillis();
- while (conn.mContainerService == null && now < timeout) {
- try {
- conn.wait(timeout - now);
- } catch (InterruptedException e) {
+ int[] users;
+ if (userId == UserHandle.USER_ALL) {
+ users = sUserManager.getUserIds();
+ } else {
+ users = new int[] { userId };
+ }
+ for (int curUser : users) {
+ ClearStorageConnection conn = new ClearStorageConnection();
+ if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE, curUser)) {
+ try {
+ long timeout = SystemClock.uptimeMillis() + 5000;
+ synchronized (conn) {
+ long now = SystemClock.uptimeMillis();
+ while (conn.mContainerService == null && now < timeout) {
+ try {
+ conn.wait(timeout - now);
+ } catch (InterruptedException e) {
+ }
}
}
- }
- if (conn.mContainerService == null) {
- return;
- }
- final File externalCacheDir = Environment
- .getExternalStorageAppCacheDirectory(packageName);
- try {
- conn.mContainerService.clearDirectory(externalCacheDir.toString());
- } catch (RemoteException e) {
- }
- if (allData) {
- final File externalDataDir = Environment
- .getExternalStorageAppDataDirectory(packageName);
+ if (conn.mContainerService == null) {
+ return;
+ }
+ final File externalCacheDir = Environment
+ .getExternalStorageAppCacheDirectory(packageName);
try {
- conn.mContainerService.clearDirectory(externalDataDir.toString());
+ conn.mContainerService.clearDirectory(externalCacheDir.toString());
} catch (RemoteException e) {
}
- final File externalMediaDir = Environment
- .getExternalStorageAppMediaDirectory(packageName);
- try {
- conn.mContainerService.clearDirectory(externalMediaDir.toString());
- } catch (RemoteException e) {
+ if (allData) {
+ final File externalDataDir = Environment
+ .getExternalStorageAppDataDirectory(packageName);
+ try {
+ conn.mContainerService.clearDirectory(externalDataDir.toString());
+ } catch (RemoteException e) {
+ }
+ final File externalMediaDir = Environment
+ .getExternalStorageAppMediaDirectory(packageName);
+ try {
+ conn.mContainerService.clearDirectory(externalMediaDir.toString());
+ } catch (RemoteException e) {
+ }
}
+ } finally {
+ mContext.unbindService(conn);
}
- } finally {
- mContext.unbindService(conn);
}
}
}
@@ -7922,7 +8175,7 @@
synchronized (mInstallLock) {
succeeded = clearApplicationUserDataLI(packageName, userId);
}
- clearExternalStorageDataSync(packageName, true);
+ clearExternalStorageDataSync(packageName, userId, true);
if (succeeded) {
// invoke DeviceStorageMonitor's update method to clear any notifications
DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
@@ -7996,7 +8249,7 @@
synchronized (mInstallLock) {
succeded = deleteApplicationCacheFilesLI(packageName, userId);
}
- clearExternalStorageDataSync(packageName, false);
+ clearExternalStorageDataSync(packageName, userId, false);
if(observer != null) {
try {
observer.onRemoveCompleted(packageName, succeded);
@@ -8454,7 +8707,7 @@
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
extras.putInt(Intent.EXTRA_UID, packageUid);
sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null,
- UserHandle.getUserId(packageUid));
+ new int[] {UserHandle.getUserId(packageUid)});
}
public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
@@ -9059,7 +9312,7 @@
if (DEBUG_SD_INSTALL)
Log.i(TAG, "Loading packages");
loadMediaPackages(processCids, uidArr, removeCids);
- startCleaningPackages();
+ startCleaningPackages(-1);
} else {
if (DEBUG_SD_INSTALL)
Log.i(TAG, "Unloading packages");
@@ -9080,7 +9333,7 @@
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
: Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserHandle.USER_ALL);
+ sendPackageBroadcast(action, null, extras, null, finishedReceiver, null);
}
}
@@ -9125,7 +9378,7 @@
doGc = true;
synchronized (mInstallLock) {
final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags,
- 0, 0);
+ 0, 0, null);
// Scan the package
if (pkg != null) {
/*
@@ -9234,8 +9487,8 @@
// Delete package internally
PackageRemovedInfo outInfo = new PackageRemovedInfo();
synchronized (mInstallLock) {
- boolean res = deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
- outInfo, false);
+ boolean res = deletePackageLI(pkgName, null, false,
+ PackageManager.DELETE_KEEP_DATA, outInfo, false);
if (res) {
pkgList.add(pkgName);
} else {
@@ -9272,9 +9525,12 @@
}
}
+ /** Binder call */
+ @Override
public void movePackage(final String packageName, final IPackageMoveObserver observer,
final int flags) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
+ UserHandle user = new UserHandle(UserHandle.getCallingUserId());
int returnCode = PackageManager.MOVE_SUCCEEDED;
int currFlags = 0;
int newFlags = 0;
@@ -9325,14 +9581,15 @@
* anyway.
*/
if (returnCode != PackageManager.MOVE_SUCCEEDED) {
- processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1),
+ processPendingMove(new MoveParams(null, observer, 0, packageName,
+ null, -1, user),
returnCode);
} else {
Message msg = mHandler.obtainMessage(INIT_COPY);
InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir);
MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
- pkg.applicationInfo.dataDir, pkg.applicationInfo.uid);
+ pkg.applicationInfo.dataDir, pkg.applicationInfo.uid, user);
msg.obj = mp;
mHandler.sendMessage(msg);
}
@@ -9524,15 +9781,36 @@
}
/** Called by UserManagerService */
- void cleanUpUser(int userHandle) {
+ void cleanUpUserLILPw(int userHandle) {
// Disable all the packages for the user first
- synchronized (mPackages) {
- Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
- for (Entry<String, PackageSetting> entry : entries) {
- entry.getValue().removeUser(userHandle);
+ Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userHandle);
+ }
+ if (mDirtyUsers.remove(userHandle));
+ mSettings.removeUserLPr(userHandle);
+ if (mInstaller != null) {
+ // Technically, we shouldn't be doing this with the package lock
+ // held. However, this is very rare, and there is already so much
+ // other disk I/O going on, that we'll let it slide for now.
+ mInstaller.removeUserDataDirs(userHandle);
+ }
+ }
+
+ /** Called by UserManagerService */
+ void createNewUserLILPw(int userHandle, File path) {
+ if (mInstaller != null) {
+ path.mkdir();
+ FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IXOTH, -1, -1);
+ for (PackageSetting ps : mSettings.mPackages.values()) {
+ // Only system apps are initially installed.
+ ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+ // Need to create a data directory for all apps under this user.
+ mInstaller.createUserData(ps.name,
+ UserHandle.getUid(userHandle, ps.appId), userHandle);
}
- if (mDirtyUsers.remove(userHandle));
- mSettings.removeUserLPr(userHandle);
+ mSettings.writePackageRestrictionsLPr(userHandle);
}
}
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index 56f2166..6d31f0e 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -20,11 +20,13 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import android.content.pm.PackageUserState;
+import android.content.pm.UserInfo;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import java.io.File;
import java.util.HashSet;
+import java.util.List;
/**
* Settings base class for pending and resolved classes.
@@ -62,19 +64,11 @@
boolean permissionsFixed;
boolean haveGids;
+ private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
+
// Whether this package is currently stopped, thus can not be
// started until explicitly launched by the user.
- private SparseArray<Boolean> stopped = new SparseArray<Boolean>();
-
- // Set to true if we have never launched this app.
- private SparseArray<Boolean> notLaunched = new SparseArray<Boolean>();
-
- /* Explicitly disabled components */
- private SparseArray<HashSet<String>> disabledComponents = new SparseArray<HashSet<String>>();
- /* Explicitly enabled components */
- private SparseArray<HashSet<String>> enabledComponents = new SparseArray<HashSet<String>>();
- /* Enabled state */
- private SparseIntArray enabled = new SparseIntArray();
+ private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
int installStatus = PKG_INSTALL_COMPLETE;
@@ -115,12 +109,11 @@
permissionsFixed = base.permissionsFixed;
haveGids = base.haveGids;
- notLaunched = base.notLaunched;
-
- disabledComponents = (SparseArray<HashSet<String>>) base.disabledComponents.clone();
- enabledComponents = (SparseArray<HashSet<String>>) base.enabledComponents.clone();
- enabled = (SparseIntArray) base.enabled.clone();
- stopped = (SparseArray<Boolean>) base.stopped.clone();
+ userState.clear();
+ for (int i=0; i<base.userState.size(); i++) {
+ userState.put(base.userState.keyAt(i),
+ new PackageUserState(base.userState.valueAt(i)));
+ }
installStatus = base.installStatus;
origPackage = base.origPackage;
@@ -171,103 +164,174 @@
signatures = base.signatures;
permissionsFixed = base.permissionsFixed;
haveGids = base.haveGids;
- stopped = base.stopped;
- notLaunched = base.notLaunched;
- disabledComponents = base.disabledComponents;
- enabledComponents = base.enabledComponents;
- enabled = base.enabled;
+ userState.clear();
+ for (int i=0; i<base.userState.size(); i++) {
+ userState.put(base.userState.keyAt(i), base.userState.valueAt(i));
+ }
installStatus = base.installStatus;
}
+ private PackageUserState modifyUserState(int userId) {
+ PackageUserState state = userState.get(userId);
+ if (state == null) {
+ state = new PackageUserState();
+ userState.put(userId, state);
+ }
+ return state;
+ }
+
+ public PackageUserState readUserState(int userId) {
+ PackageUserState state = userState.get(userId);
+ return state != null ? state : DEFAULT_USER_STATE;
+ }
+
void setEnabled(int state, int userId) {
- enabled.put(userId, state);
+ modifyUserState(userId).enabled = state;
}
int getEnabled(int userId) {
- return enabled.get(userId, COMPONENT_ENABLED_STATE_DEFAULT);
+ return readUserState(userId).enabled;
+ }
+
+ void setInstalled(boolean inst, int userId) {
+ modifyUserState(userId).installed = inst;
+ }
+
+ boolean getInstalled(int userId) {
+ return readUserState(userId).installed;
+ }
+
+ boolean isAnyInstalled(int[] users) {
+ for (int user: users) {
+ if (readUserState(user).installed) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int[] getInstalledUsers(int[] users) {
+ int num = 0;
+ for (int user : users) {
+ if (getInstalled(user)) {
+ num++;
+ }
+ }
+ int[] res = new int[num];
+ num = 0;
+ for (int user : users) {
+ if (getInstalled(user)) {
+ res[num] = user;
+ num++;
+ }
+ }
+ return res;
}
boolean getStopped(int userId) {
- return stopped.get(userId, false);
+ return readUserState(userId).stopped;
}
void setStopped(boolean stop, int userId) {
- stopped.put(userId, stop);
+ modifyUserState(userId).stopped = stop;
}
boolean getNotLaunched(int userId) {
- return notLaunched.get(userId, false);
+ return readUserState(userId).notLaunched;
}
void setNotLaunched(boolean stop, int userId) {
- notLaunched.put(userId, stop);
+ modifyUserState(userId).notLaunched = stop;
+ }
+
+ void setUserState(int userId, int enabled, boolean installed, boolean stopped,
+ boolean notLaunched, HashSet<String> enabledComponents,
+ HashSet<String> disabledComponents) {
+ PackageUserState state = modifyUserState(userId);
+ state.enabled = enabled;
+ state.installed = installed;
+ state.stopped = stopped;
+ state.notLaunched = notLaunched;
+ state.enabledComponents = enabledComponents;
+ state.disabledComponents = disabledComponents;
}
HashSet<String> getEnabledComponents(int userId) {
- return getComponentHashSet(enabledComponents, userId);
+ return readUserState(userId).enabledComponents;
}
HashSet<String> getDisabledComponents(int userId) {
- return getComponentHashSet(disabledComponents, userId);
+ return readUserState(userId).disabledComponents;
}
void setEnabledComponents(HashSet<String> components, int userId) {
- enabledComponents.put(userId, components);
+ modifyUserState(userId).enabledComponents = components;
}
void setDisabledComponents(HashSet<String> components, int userId) {
- disabledComponents.put(userId, components);
+ modifyUserState(userId).disabledComponents = components;
}
- private HashSet<String> getComponentHashSet(SparseArray<HashSet<String>> setArray, int userId) {
- HashSet<String> set = setArray.get(userId);
- if (set == null) {
- set = new HashSet<String>(1);
- setArray.put(userId, set);
+ void setEnabledComponentsCopy(HashSet<String> components, int userId) {
+ modifyUserState(userId).enabledComponents = components != null
+ ? new HashSet<String>(components) : null;
+ }
+
+ void setDisabledComponentsCopy(HashSet<String> components, int userId) {
+ modifyUserState(userId).disabledComponents = components != null
+ ? new HashSet<String>(components) : null;
+ }
+
+ PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
+ PackageUserState state = modifyUserState(userId);
+ if (disabled && state.disabledComponents == null) {
+ state.disabledComponents = new HashSet<String>(1);
}
- return set;
+ if (enabled && state.enabledComponents == null) {
+ state.enabledComponents = new HashSet<String>(1);
+ }
+ return state;
}
void addDisabledComponent(String componentClassName, int userId) {
- HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
- disabled.add(componentClassName);
+ modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
}
void addEnabledComponent(String componentClassName, int userId) {
- HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
- enabled.add(componentClassName);
+ modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
}
boolean enableComponentLPw(String componentClassName, int userId) {
- HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
- HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
- boolean changed = disabled.remove(componentClassName);
- changed |= enabled.add(componentClassName);
+ PackageUserState state = modifyUserStateComponents(userId, false, true);
+ boolean changed = state.disabledComponents != null
+ ? state.disabledComponents.remove(componentClassName) : false;
+ changed |= state.enabledComponents.add(componentClassName);
return changed;
}
boolean disableComponentLPw(String componentClassName, int userId) {
- HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
- HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
- boolean changed = enabled.remove(componentClassName);
- changed |= disabled.add(componentClassName);
+ PackageUserState state = modifyUserStateComponents(userId, true, false);
+ boolean changed = state.enabledComponents != null
+ ? state.enabledComponents.remove(componentClassName) : false;
+ changed |= state.disabledComponents.add(componentClassName);
return changed;
}
boolean restoreComponentLPw(String componentClassName, int userId) {
- HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
- HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
- boolean changed = enabled.remove(componentClassName);
- changed |= disabled.remove(componentClassName);
+ PackageUserState state = modifyUserStateComponents(userId, true, true);
+ boolean changed = state.disabledComponents != null
+ ? state.disabledComponents.remove(componentClassName) : false;
+ changed |= state.enabledComponents != null
+ ? state.enabledComponents.remove(componentClassName) : false;
return changed;
}
int getCurrentEnabledStateLPr(String componentName, int userId) {
- HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
- HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
- if (enabled.contains(componentName)) {
+ PackageUserState state = readUserState(userId);
+ if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) {
return COMPONENT_ENABLED_STATE_ENABLED;
- } else if (disabled.contains(componentName)) {
+ } else if (state.disabledComponents != null
+ && state.disabledComponents.contains(componentName)) {
return COMPONENT_ENABLED_STATE_DISABLED;
} else {
return COMPONENT_ENABLED_STATE_DEFAULT;
@@ -275,11 +339,6 @@
}
void removeUser(int userId) {
- enabled.delete(userId);
- stopped.delete(userId);
- enabledComponents.delete(userId);
- disabledComponents.delete(userId);
- notLaunched.delete(userId);
+ userState.delete(userId);
}
-
}
diff --git a/services/java/com/android/server/pm/PackageVerificationState.java b/services/java/com/android/server/pm/PackageVerificationState.java
index e5b89c1..3214e88 100644
--- a/services/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/java/com/android/server/pm/PackageVerificationState.java
@@ -43,6 +43,8 @@
private boolean mRequiredVerificationPassed;
+ private boolean mExtendedTimeout;
+
/**
* Create a new package verification state where {@code requiredVerifierUid}
* is the user ID for the package that must reply affirmative before things
@@ -55,6 +57,7 @@
mRequiredVerifierUid = requiredVerifierUid;
mArgs = args;
mSufficientVerifierUids = new SparseBooleanArray();
+ mExtendedTimeout = false;
}
public InstallArgs getInstallArgs() {
@@ -146,4 +149,22 @@
return true;
}
+
+ /**
+ * Extend the timeout for this Package to be verified.
+ */
+ public void extendTimeout() {
+ if (!mExtendedTimeout) {
+ mExtendedTimeout = true;
+ }
+ }
+
+ /**
+ * Returns whether the timeout was extended for verification.
+ *
+ * @return {@code true} if a timeout was already extended.
+ */
+ public boolean timeoutExtended() {
+ return mExtendedTimeout;
+ }
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index cfc0f5c..68b594a 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -38,11 +38,13 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
+import android.content.pm.PackageCleanItem;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
+import android.content.pm.PackageUserState;
import android.content.pm.VerifierDeviceIdentity;
import android.os.Binder;
import android.os.Environment;
@@ -92,9 +94,12 @@
private static final String TAG_PACKAGE = "pkg";
private static final String ATTR_NAME = "name";
+ private static final String ATTR_USER = "user";
+ private static final String ATTR_CODE = "code";
private static final String ATTR_NOT_LAUNCHED = "nl";
private static final String ATTR_ENABLED = "enabled";
private static final String ATTR_STOPPED = "stopped";
+ private static final String ATTR_INSTALLED = "inst";
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
@@ -156,7 +161,8 @@
// Packages that have been uninstalled and still need their external
// storage data deleted.
- final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
+ final SparseArray<ArrayList<PackageCleanItem>> mPackagesToBeCleaned
+ = new SparseArray<ArrayList<PackageCleanItem>>();
// Packages that have been renamed since they were first installed.
// Keys are the new names of the packages, values are the original
@@ -200,10 +206,11 @@
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
+ String nativeLibraryPathString, int pkgFlags, UserHandle user, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
- resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
+ resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags,
+ user, add);
return p;
}
@@ -364,7 +371,8 @@
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
+ String nativeLibraryPathString, int vc, int pkgFlags,
+ UserHandle installUser, boolean add) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (!p.codePath.equals(codePath)) {
@@ -407,11 +415,6 @@
}
}
if (p == null) {
- // Create a new PackageSettings entry. this can end up here because
- // of code path mismatch or user id mismatch of an updated system partition
- if (!create) {
- return null;
- }
if (origPackage != null) {
// We are consuming the data from an existing package.
p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
@@ -445,8 +448,20 @@
List<UserInfo> users = getAllUsers();
if (users != null) {
for (UserInfo user : users) {
- p.setStopped(true, user.id);
- p.setNotLaunched(true, user.id);
+ // By default we consider this app to be installed
+ // for the user if no user has been specified (which
+ // means to leave it at its original value, and the
+ // original default value is true), or we are being
+ // asked to install for all users, or this is the
+ // user we are installing for.
+ final boolean installed = installUser == null
+ || installUser.getIdentifier() == UserHandle.USER_ALL
+ || installUser.getIdentifier() == user.id;
+ p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,
+ installed,
+ true, // stopped,
+ true, // notLaunched
+ null, null);
writePackageRestrictionsLPr(user.id);
}
}
@@ -472,12 +487,10 @@
if (users != null) {
for (UserInfo user : users) {
int userId = user.id;
- p.setDisabledComponents(
- new HashSet<String>(dis.getDisabledComponents(userId)),
- userId);
- p.setEnabledComponents(
- new HashSet<String>(dis.getEnabledComponents(userId)),
- userId);
+ p.setDisabledComponentsCopy(
+ dis.getDisabledComponents(userId), userId);
+ p.setEnabledComponentsCopy(
+ dis.getEnabledComponents(userId), userId);
}
}
// Add new setting to list of user ids
@@ -498,6 +511,25 @@
// user preferences
addPackageSettingLPw(p, name, sharedUser);
}
+ } else {
+ if (installUser != null) {
+ // The caller has explicitly specified the user they want this
+ // package installed for, and the package already exists.
+ // Make sure it conforms to the new request.
+ List<UserInfo> users = getAllUsers();
+ if (users != null) {
+ for (UserInfo user : users) {
+ if (installUser.getIdentifier() == UserHandle.USER_ALL
+ || installUser.getIdentifier() == user.id) {
+ boolean installed = p.getInstalled(user.id);
+ if (!installed) {
+ p.setInstalled(true, user.id);
+ writePackageRestrictionsLPr(user.id);
+ }
+ }
+ }
+ }
+ }
}
return p;
}
@@ -778,10 +810,14 @@
+ "assuming all started");
// At first boot, make sure no packages are stopped.
// We usually want to have third party apps initialize
- // in the stopped state, but not at first boot.
+ // in the stopped state, but not at first boot. Also
+ // consider all applications to be installed.
for (PackageSetting pkg : mPackages.values()) {
- pkg.setStopped(false, userId);
- pkg.setNotLaunched(false, userId);
+ pkg.setUserState(userId, COMPONENT_ENABLED_STATE_DEFAULT,
+ true, // installed
+ false, // stopped
+ false, // notLaunched
+ null, null);
}
return;
}
@@ -823,17 +859,21 @@
XmlUtils.skipCurrentTag(parser);
continue;
}
- String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
- int enabled = enabledStr == null ? COMPONENT_ENABLED_STATE_DEFAULT
- : Integer.parseInt(enabledStr);
- ps.setEnabled(enabled, userId);
- String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED);
- boolean stopped = stoppedStr == null ? false : Boolean.parseBoolean(stoppedStr);
- ps.setStopped(stopped, userId);
- String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
- boolean notLaunched = stoppedStr == null ? false
- : Boolean.parseBoolean(notLaunchedStr);
- ps.setNotLaunched(notLaunched, userId);
+ final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
+ final int enabled = enabledStr == null
+ ? COMPONENT_ENABLED_STATE_DEFAULT : Integer.parseInt(enabledStr);
+ final String installedStr = parser.getAttributeValue(null, ATTR_INSTALLED);
+ final boolean installed = installedStr == null
+ ? true : Boolean.parseBoolean(installedStr);
+ final String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED);
+ final boolean stopped = stoppedStr == null
+ ? false : Boolean.parseBoolean(stoppedStr);
+ final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
+ final boolean notLaunched = stoppedStr == null
+ ? false : Boolean.parseBoolean(notLaunchedStr);
+
+ HashSet<String> enabledComponents = null;
+ HashSet<String> disabledComponents = null;
int packageDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -845,13 +885,14 @@
}
tagName = parser.getName();
if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
- HashSet<String> components = readComponentsLPr(parser);
- ps.setEnabledComponents(components, userId);
+ enabledComponents = readComponentsLPr(parser);
} else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
- HashSet<String> components = readComponentsLPr(parser);
- ps.setDisabledComponents(components, userId);
+ disabledComponents = readComponentsLPr(parser);
}
}
+
+ ps.setUserState(userId, enabled, installed, stopped, notLaunched,
+ enabledComponents, disabledComponents);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -876,7 +917,7 @@
private HashSet<String> readComponentsLPr(XmlPullParser parser)
throws IOException, XmlPullParserException {
- HashSet<String> components = new HashSet<String>();
+ HashSet<String> components = null;
int type;
int outerDepth = parser.getDepth();
String tagName;
@@ -891,6 +932,9 @@
if (tagName.equals(TAG_ITEM)) {
String componentName = parser.getAttributeValue(null, ATTR_NAME);
if (componentName != null) {
+ if (components == null) {
+ components = new HashSet<String>();
+ }
components.add(componentName);
}
}
@@ -936,41 +980,44 @@
serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
for (final PackageSetting pkg : mPackages.values()) {
- if (pkg.getStopped(userId)
- || pkg.getNotLaunched(userId)
- || pkg.getEnabled(userId) != COMPONENT_ENABLED_STATE_DEFAULT
- || pkg.getEnabledComponents(userId).size() > 0
- || pkg.getDisabledComponents(userId).size() > 0) {
+ PackageUserState ustate = pkg.readUserState(userId);
+ if (ustate.stopped || ustate.notLaunched || !ustate.installed
+ || ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
+ || (ustate.enabledComponents != null
+ && ustate.enabledComponents.size() > 0)
+ || (ustate.disabledComponents != null
+ && ustate.disabledComponents.size() > 0)) {
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, pkg.name);
- boolean stopped = pkg.getStopped(userId);
- boolean notLaunched = pkg.getNotLaunched(userId);
- int enabled = pkg.getEnabled(userId);
- if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + enabled);
- HashSet<String> enabledComponents = pkg.getEnabledComponents(userId);
- HashSet<String> disabledComponents = pkg.getDisabledComponents(userId);
+ if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
- if (stopped) {
+ if (!ustate.installed) {
+ serializer.attribute(null, ATTR_INSTALLED, "false");
+ }
+ if (ustate.stopped) {
serializer.attribute(null, ATTR_STOPPED, "true");
}
- if (notLaunched) {
+ if (ustate.notLaunched) {
serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
}
- if (enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
- serializer.attribute(null, ATTR_ENABLED, Integer.toString(enabled));
+ if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attribute(null, ATTR_ENABLED,
+ Integer.toString(ustate.enabled));
}
- if (enabledComponents.size() > 0) {
+ if (ustate.enabledComponents != null
+ && ustate.enabledComponents.size() > 0) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
- for (final String name : enabledComponents) {
+ for (final String name : ustate.enabledComponents) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, TAG_ENABLED_COMPONENTS);
}
- if (disabledComponents.size() > 0) {
+ if (ustate.disabledComponents != null
+ && ustate.disabledComponents.size() > 0) {
serializer.startTag(null, TAG_DISABLED_COMPONENTS);
- for (final String name : disabledComponents) {
+ for (final String name : ustate.disabledComponents) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
@@ -1210,9 +1257,17 @@
if (mPackagesToBeCleaned.size() > 0) {
for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
- serializer.startTag(null, "cleaning-package");
- serializer.attribute(null, ATTR_NAME, mPackagesToBeCleaned.get(i));
- serializer.endTag(null, "cleaning-package");
+ final int userId = mPackagesToBeCleaned.keyAt(i);
+ final String userStr = Integer.toString(userId);
+ final ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.valueAt(i);
+ for (int j=0; j<pkgs.size(); j++) {
+ serializer.startTag(null, "cleaning-package");
+ PackageCleanItem item = pkgs.get(i);
+ serializer.attribute(null, ATTR_NAME, item.packageName);
+ serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
+ serializer.attribute(null, ATTR_USER, userStr);
+ serializer.endTag(null, "cleaning-package");
+ }
}
}
@@ -1468,6 +1523,17 @@
return ret;
}
+ void addPackageToCleanLPw(int userId, PackageCleanItem pkg) {
+ ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.get(userId);
+ if (pkgs == null) {
+ pkgs = new ArrayList<PackageCleanItem>();
+ mPackagesToBeCleaned.put(userId, pkgs);
+ }
+ if (!pkgs.contains(pkg)) {
+ pkgs.add(pkg);
+ }
+ }
+
boolean readLPw(List<UserInfo> users) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
@@ -1545,8 +1611,21 @@
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
String name = parser.getAttributeValue(null, ATTR_NAME);
+ String userStr = parser.getAttributeValue(null, ATTR_USER);
+ String codeStr = parser.getAttributeValue(null, ATTR_CODE);
if (name != null) {
- mPackagesToBeCleaned.add(name);
+ int user = 0;
+ boolean andCode = true;
+ try {
+ if (userStr != null) {
+ user = Integer.parseInt(userStr);
+ }
+ } catch (NumberFormatException e) {
+ }
+ if (codeStr != null) {
+ andCode = Boolean.parseBoolean(codeStr);
+ }
+ addPackageToCleanLPw(user, new PackageCleanItem(name, andCode));
}
} else if (tagName.equals("renamed-package")) {
String nname = parser.getAttributeValue(null, "new");
@@ -1623,7 +1702,8 @@
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
- pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
+ pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags,
+ UserHandle.ALL, true);
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unable to create application package for " + pp.name);
@@ -2292,6 +2372,10 @@
return ps;
}
+ private String compToString(HashSet<String> cmp) {
+ return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
+ }
+
boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
return true;
@@ -2302,24 +2386,26 @@
Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = "
+ componentInfo.packageName + " componentName = " + componentInfo.name);
Log.v(PackageManagerService.TAG, "enabledComponents: "
- + Arrays.toString(packageSettings.getEnabledComponents(userId).toArray()));
+ + compToString(packageSettings.getEnabledComponents(userId)));
Log.v(PackageManagerService.TAG, "disabledComponents: "
- + Arrays.toString(packageSettings.getDisabledComponents(userId).toArray()));
+ + compToString(packageSettings.getDisabledComponents(userId)));
}
if (packageSettings == null) {
return false;
}
- final int enabled = packageSettings.getEnabled(userId);
- if (enabled == COMPONENT_ENABLED_STATE_DISABLED
- || enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
+ PackageUserState ustate = packageSettings.readUserState(userId);
+ if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED
+ || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
|| (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
- && enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
+ && ustate.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
return false;
}
- if (packageSettings.getEnabledComponents(userId).contains(componentInfo.name)) {
+ if (ustate.enabledComponents != null
+ && ustate.enabledComponents.contains(componentInfo.name)) {
return true;
}
- if (packageSettings.getDisabledComponents(userId).contains(componentInfo.name)) {
+ if (ustate.disabledComponents != null
+ && ustate.disabledComponents.contains(componentInfo.name)) {
return false;
}
return componentInfo.enabled;
@@ -2378,7 +2464,7 @@
if (pkgSetting.installerPackageName != null) {
PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
pkgSetting.name, null,
- pkgSetting.installerPackageName, null, userId);
+ pkgSetting.installerPackageName, null, new int[] {userId});
}
pkgSetting.setNotLaunched(false, userId);
}
@@ -2390,7 +2476,7 @@
private List<UserInfo> getAllUsers() {
long id = Binder.clearCallingIdentity();
try {
- return UserManagerService.getInstance(mContext).getUsers();
+ return UserManagerService.getInstance().getUsers();
} catch (NullPointerException npe) {
// packagemanager not yet initialized
} finally {
@@ -2427,7 +2513,6 @@
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
- ApplicationInfo.FLAG_STOPPED, "STOPPED",
ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
@@ -2537,22 +2622,28 @@
pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
pw.print(" haveGids="); pw.println(ps.haveGids);
pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
- pw.print(" installStatus="); pw.print(ps.installStatus);
+ pw.print(" installStatus="); pw.println(ps.installStatus);
for (UserInfo user : users) {
- pw.print(" User "); pw.print(user.id); pw.print(": ");
+ pw.print(" User "); pw.print(user.id); pw.print(": ");
+ pw.print(" installed=");
+ pw.print(ps.getInstalled(user.id));
pw.print(" stopped=");
pw.print(ps.getStopped(user.id));
+ pw.print(" notLaunched=");
+ pw.print(ps.getNotLaunched(user.id));
pw.print(" enabled=");
pw.println(ps.getEnabled(user.id));
- if (ps.getDisabledComponents(user.id).size() > 0) {
- pw.println(" disabledComponents:");
- for (String s : ps.getDisabledComponents(user.id)) {
+ HashSet<String> cmp = ps.getDisabledComponents(user.id);
+ if (cmp != null && cmp.size() > 0) {
+ pw.println(" disabledComponents:");
+ for (String s : cmp) {
pw.print(" "); pw.println(s);
}
}
- if (ps.getEnabledComponents(user.id).size() > 0) {
- pw.println(" enabledComponents:");
- for (String s : ps.getEnabledComponents(user.id)) {
+ cmp = ps.getEnabledComponents(user.id);
+ if (cmp != null && cmp.size() > 0) {
+ pw.println(" enabledComponents:");
+ for (String s : cmp) {
pw.print(" "); pw.println(s);
}
}
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index c292bbc..750aa72 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -25,7 +25,6 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Binder;
@@ -34,10 +33,8 @@
import android.os.IUserManager;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.AtomicFile;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -72,59 +69,79 @@
private static final String USER_LIST_FILENAME = "userlist.xml";
private static final String USER_PHOTO_FILENAME = "photo.png";
- private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+ private final Context mContext;
+ private final PackageManagerService mPm;
+ private final Object mInstallLock;
+ private final Object mPackagesLock;
private final File mUsersDir;
private final File mUserListFile;
+ private final File mBaseUserPath;
+
+ private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
- private Installer mInstaller;
- private File mBaseUserPath;
- private Context mContext;
private static UserManagerService sInstance;
- private PackageManagerService mPm;
- public synchronized static UserManagerService getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new UserManagerService(context);
+ public static UserManagerService getInstance() {
+ synchronized (UserManagerService.class) {
+ return sInstance;
}
- return sInstance;
}
/**
* Available for testing purposes.
*/
UserManagerService(File dataDir, File baseUserPath) {
- mUsersDir = new File(dataDir, USER_INFO_DIR);
- mUsersDir.mkdirs();
- // Make zeroth user directory, for services to migrate their files to that location
- File userZeroDir = new File(mUsersDir, "0");
- userZeroDir.mkdirs();
- mBaseUserPath = baseUserPath;
- FileUtils.setPermissions(mUsersDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
- readUserList();
+ this(null, null, new Object(), new Object(), dataDir, baseUserPath);
}
- public UserManagerService(Context context) {
- this(Environment.getDataDirectory(), new File(Environment.getDataDirectory(), "user"));
- mContext = context;
+ /**
+ * Called by package manager to create the service. This is closely
+ * associated with the package manager, and the given lock is the
+ * package manager's own lock.
+ */
+ UserManagerService(Context context, PackageManagerService pm,
+ Object installLock, Object packagesLock) {
+ this(context, pm, installLock, packagesLock,
+ Environment.getDataDirectory(),
+ new File(Environment.getDataDirectory(), "user"));
}
- void setInstaller(PackageManagerService pm, Installer installer) {
- mInstaller = installer;
- mPm = pm;
+ /**
+ * Available for testing purposes.
+ */
+ private UserManagerService(Context context, PackageManagerService pm,
+ Object installLock, Object packagesLock,
+ File dataDir, File baseUserPath) {
+ synchronized (UserManagerService.class) {
+ mContext = context;
+ mPm = pm;
+ mInstallLock = installLock;
+ mPackagesLock = packagesLock;
+ mUsersDir = new File(dataDir, USER_INFO_DIR);
+ mUsersDir.mkdirs();
+ // Make zeroth user directory, for services to migrate their files to that location
+ File userZeroDir = new File(mUsersDir, "0");
+ userZeroDir.mkdirs();
+ mBaseUserPath = baseUserPath;
+ FileUtils.setPermissions(mUsersDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
+ readUserList();
+ sInstance = this;
+ }
}
@Override
public List<UserInfo> getUsers() {
checkManageUsersPermission("query users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
for (int i = 0; i < mUsers.size(); i++) {
users.add(mUsers.valueAt(i));
@@ -136,14 +153,20 @@
@Override
public UserInfo getUserInfo(int userId) {
checkManageUsersPermission("query user");
- synchronized (mUsers) {
- UserInfo info = mUsers.get(userId);
- return info;
+ synchronized (mPackagesLock) {
+ return getUserInfoLocked(userId);
}
}
+ /*
+ * Should be locked on mUsers before calling this.
+ */
+ private UserInfo getUserInfoLocked(int userId) {
+ return mUsers.get(userId);
+ }
+
public boolean exists(int userId) {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
return ArrayUtils.contains(mUserIds, userId);
}
}
@@ -151,7 +174,7 @@
@Override
public void setUserName(int userId, String name) {
checkManageUsersPermission("rename users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
if (name != null && !name.equals(info.name)) {
info.name = name;
@@ -163,7 +186,7 @@
@Override
public ParcelFileDescriptor setUserIcon(int userId) {
checkManageUsersPermission("update users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
if (info == null) return null;
ParcelFileDescriptor fd = updateIconBitmapLocked(info);
@@ -177,7 +200,7 @@
@Override
public void setGuestEnabled(boolean enable) {
checkManageUsersPermission("enable guest users");
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
if (mGuestEnabled != enable) {
mGuestEnabled = enable;
// Erase any guest user that currently exists
@@ -200,7 +223,7 @@
@Override
public boolean isGuestEnabled() {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
return mGuestEnabled;
}
}
@@ -212,8 +235,9 @@
}
/**
- * Enforces that only the system UID or root's UID can call a method exposed
- * via Binder.
+ * Enforces that only the system UID or root's UID or apps that have the
+ * {@link android.Manifest.permission.MANAGE_USERS MANAGE_USERS}
+ * permission can make certain calls to the UserManager.
*
* @param message used as message if SecurityException is thrown
* @throws SecurityException if the caller is not system or root
@@ -255,11 +279,17 @@
* @return the array of user ids.
*/
int[] getUserIds() {
+ synchronized (mPackagesLock) {
+ return mUserIds;
+ }
+ }
+
+ int[] getUserIdsLPr() {
return mUserIds;
}
private void readUserList() {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
readUserListLocked();
}
}
@@ -492,15 +522,15 @@
int userId = getNextAvailableId();
UserInfo userInfo = new UserInfo(userId, name, null, flags);
File userPath = new File(mBaseUserPath, Integer.toString(userId));
- if (!createPackageFolders(userId, userPath)) {
- return null;
- }
- synchronized (mUsers) {
- userInfo.serialNumber = mNextSerialNumber++;
- mUsers.put(userId, userInfo);
- writeUserListLocked();
- writeUserLocked(userInfo);
- updateUserIdsLocked();
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ userInfo.serialNumber = mNextSerialNumber++;
+ mUsers.put(userId, userInfo);
+ writeUserListLocked();
+ writeUserLocked(userInfo);
+ updateUserIdsLocked();
+ mPm.createNewUserLILPw(userId, userPath);
+ }
}
if (userInfo != null) {
Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
@@ -519,95 +549,62 @@
*/
public boolean removeUser(int userHandle) {
checkManageUsersPermission("Only the system can remove users");
- boolean result;
- synchronized (mUsers) {
- result = removeUserLocked(userHandle);
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ final UserInfo user = mUsers.get(userHandle);
+ if (userHandle == 0 || user == null) {
+ return false;
+ }
+
+ // Cleanup package manager settings
+ mPm.cleanUpUserLILPw(userHandle);
+
+ // Remove this user from the list
+ mUsers.remove(userHandle);
+ // Remove user file
+ AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
+ userFile.delete();
+ // Update the user list
+ writeUserListLocked();
+ updateUserIdsLocked();
+ }
}
+
// Let other services shutdown any activity
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
- return result;
+ return true;
}
@Override
public int getUserSerialNumber(int userHandle) {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
if (!exists(userHandle)) return -1;
- return getUserInfo(userHandle).serialNumber;
+ return getUserInfoLocked(userHandle).serialNumber;
}
}
@Override
public int getUserHandle(int userSerialNumber) {
- synchronized (mUsers) {
+ synchronized (mPackagesLock) {
for (int userId : mUserIds) {
- if (getUserInfo(userId).serialNumber == userSerialNumber) return userId;
+ if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
}
// Not found
return -1;
}
}
- private boolean removeUserLocked(int userHandle) {
- final UserInfo user = mUsers.get(userHandle);
- if (userHandle == 0 || user == null) {
- return false;
- }
-
- mPm.cleanUpUser(userHandle);
-
- // Remove this user from the list
- mUsers.remove(userHandle);
- // Remove user file
- AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
- userFile.delete();
- // Update the user list
- writeUserListLocked();
- updateUserIdsLocked();
-
- removePackageFolders(userHandle);
- return true;
- }
-
- public void installPackageForAllUsers(String packageName, int uid) {
- for (int userId : mUserIds) {
- // Don't do it for the primary user, it will become recursive.
- if (userId == 0)
- continue;
- mInstaller.createUserData(packageName, UserHandle.getUid(userId, uid),
- userId);
- }
- }
-
- public void clearUserDataForAllUsers(String packageName) {
- for (int userId : mUserIds) {
- // Don't do it for the primary user, it will become recursive.
- if (userId == 0)
- continue;
- mInstaller.clearUserData(packageName, userId);
- }
- }
-
- public void removePackageForAllUsers(String packageName) {
- for (int userId : mUserIds) {
- // Don't do it for the primary user, it will become recursive.
- if (userId == 0)
- continue;
- mInstaller.remove(packageName, userId);
- }
- }
-
/**
* Caches the list of user ids in an array, adjusting the array size when necessary.
*/
private void updateUserIdsLocked() {
- if (mUserIds == null || mUserIds.length != mUsers.size()) {
- mUserIds = new int[mUsers.size()];
- }
+ int[] newUsers = new int[mUsers.size()];
for (int i = 0; i < mUsers.size(); i++) {
- mUserIds[i] = mUsers.keyAt(i);
+ newUsers[i] = mUsers.keyAt(i);
}
+ mUserIds = newUsers;
}
/**
@@ -617,35 +614,15 @@
* @return
*/
private int getNextAvailableId() {
- int i = 0;
- while (i < Integer.MAX_VALUE) {
- if (mUsers.indexOfKey(i) < 0) {
- break;
+ synchronized (mPackagesLock) {
+ int i = 0;
+ while (i < Integer.MAX_VALUE) {
+ if (mUsers.indexOfKey(i) < 0) {
+ break;
+ }
+ i++;
}
- i++;
+ return i;
}
- return i;
- }
-
- private boolean createPackageFolders(int id, File userPath) {
- // mInstaller may not be available for unit-tests.
- if (mInstaller == null) return true;
-
- // Create the user path
- userPath.mkdir();
- FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
-
- mInstaller.cloneUserData(0, id, false);
-
- return true;
- }
-
- boolean removePackageFolders(int id) {
- // mInstaller may not be available for unit-tests.
- if (mInstaller == null) return true;
-
- mInstaller.removeUserDataDirs(id);
- return true;
}
}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index cf12b20..cd211da 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -17,6 +17,8 @@
package com.android.server.power;
import com.android.server.LightsService;
+import com.android.server.TwilightService;
+import com.android.server.TwilightService.TwilightState;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -32,7 +34,10 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
import android.os.SystemClock;
+import android.text.format.DateUtils;
+import android.util.FloatMath;
import android.util.Slog;
import android.util.Spline;
import android.util.TimeUtils;
@@ -78,8 +83,31 @@
// screen state returns. Playing the animation can also be somewhat slow.
private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
- private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 300;
- private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 600;
+ // If true, enables the use of the screen auto-brightness adjustment setting.
+ private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = false;
+
+ // The maximum range of gamma adjustment possible using the screen
+ // auto-brightness adjustment setting.
+ private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
+
+ // If true, enables the use of the current time as an auto-brightness adjustment.
+ // The basic idea here is to expand the dynamic range of auto-brightness
+ // when it is especially dark outside. The light sensor tends to perform
+ // poorly at low light levels so we compensate for it by making an
+ // assumption about the environment.
+ private static final boolean USE_TWILIGHT_ADJUSTMENT = true;
+
+ // Specifies the maximum magnitude of the time of day adjustment.
+ private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
+
+ // The amount of time after or before sunrise over which to start adjusting
+ // the gamma. We want the change to happen gradually so that it is below the
+ // threshold of perceptibility and so that the adjustment has maximum effect
+ // well after dusk.
+ private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+
+ private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
+ private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 450;
private static final int MSG_UPDATE_POWER_STATE = 1;
private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
@@ -138,6 +166,9 @@
// The lights service.
private final LightsService mLights;
+ // The twilight service.
+ private final TwilightService mTwilight;
+
// The sensor manager.
private final SensorManager mSensorManager;
@@ -150,8 +181,11 @@
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
- // Auto-brightness.
+ // True if auto-brightness should be used.
private boolean mUseSoftwareAutoBrightnessConfig;
+
+ // The auto-brightness spline adjustment.
+ // The brightness values have been scaled to a range of 0..1.
private Spline mScreenAutoBrightnessSpline;
// Amount of time to delay auto-brightness after screen on while waiting for
@@ -266,6 +300,9 @@
// Use -1 if there is no current auto-brightness value available.
private int mScreenAutoBrightness = -1;
+ // The last screen auto-brightness gamma. (For printing in dump() only.)
+ private float mLastScreenAutoBrightnessGamma = 1.0f;
+
// True if the screen auto-brightness value is actually being used to
// set the display brightness.
private boolean mUsingScreenAutoBrightness;
@@ -275,11 +312,14 @@
private ObjectAnimator mElectronBeamOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
+ // Twilight changed. We might recalculate auto-brightness values.
+ private boolean mTwilightChanged;
+
/**
* Creates the display power controller.
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
- LightsService lights, SuspendBlocker suspendBlocker,
+ LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
@@ -288,6 +328,7 @@
mCallbackHandler = callbackHandler;
mLights = lights;
+ mTwilight = twilight;
mSensorManager = new SystemSensorManager(mHandler.getLooper());
final Resources resources = context.getResources();
@@ -328,6 +369,10 @@
&& !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
+
+ if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
+ mTwilight.registerListener(mTwilightListener, mHandler);
+ }
}
private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
@@ -335,10 +380,10 @@
final int n = brightness.length;
float[] x = new float[n];
float[] y = new float[n];
- y[0] = brightness[0];
+ y[0] = (float)brightness[0] / PowerManager.BRIGHTNESS_ON;
for (int i = 1; i < n; i++) {
x[i] = lux[i - 1];
- y[i] = brightness[i];
+ y[i] = (float)brightness[i] / PowerManager.BRIGHTNESS_ON;
}
Spline spline = Spline.createMonotoneCubicSpline(x, y);
@@ -470,6 +515,9 @@
// Update the power state request.
final boolean mustNotify;
boolean mustInitialize = false;
+ boolean updateAutoBrightness = mTwilightChanged;
+ mTwilightChanged = false;
+
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
if (mPendingRequestLocked == null) {
@@ -483,6 +531,10 @@
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
+ if (mPowerRequest.screenAutoBrightnessAdjustment
+ != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
+ updateAutoBrightness = true;
+ }
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
@@ -530,19 +582,21 @@
// Turn on the light sensor if needed.
if (mLightSensor != null) {
setLightSensorEnabled(mPowerRequest.useAutoBrightness
- && wantScreenOn(mPowerRequest.screenState));
+ && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
}
// Set the screen brightness.
if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
// Screen is dimmed. Overrides everything else.
- animateScreenBrightness(mScreenBrightnessDimConfig, BRIGHTNESS_RAMP_RATE_FAST);
+ animateScreenBrightness(
+ clampScreenBrightness(mScreenBrightnessDimConfig),
+ BRIGHTNESS_RAMP_RATE_FAST);
mUsingScreenAutoBrightness = false;
} else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
// Use current auto-brightness value.
animateScreenBrightness(
- Math.max(mScreenAutoBrightness, mScreenBrightnessDimConfig),
+ clampScreenBrightness(mScreenAutoBrightness),
mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
BRIGHTNESS_RAMP_RATE_FAST);
mUsingScreenAutoBrightness = true;
@@ -552,7 +606,7 @@
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
animateScreenBrightness(
- Math.max(mPowerRequest.screenBrightness, mScreenBrightnessDimConfig),
+ clampScreenBrightness(mPowerRequest.screenBrightness),
BRIGHTNESS_RAMP_RATE_FAST);
mUsingScreenAutoBrightness = false;
}
@@ -630,6 +684,10 @@
}
}
+ private int clampScreenBrightness(int value) {
+ return Math.min(Math.max(Math.max(value, mScreenBrightnessDimConfig), 0), 255);
+ }
+
private void animateScreenBrightness(int target, int rate) {
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
mNotifier.onScreenBrightness(target);
@@ -691,9 +749,10 @@
}
}
- private void setLightSensorEnabled(boolean enable) {
+ private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
if (enable) {
if (!mLightSensorEnabled) {
+ updateAutoBrightness = true;
mLightSensorEnabled = true;
mLightSensorEnableTime = SystemClock.uptimeMillis();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
@@ -703,11 +762,13 @@
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
mLightMeasurementValid = false;
- updateAutoBrightness(false);
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mLightSensorListener);
}
}
+ if (updateAutoBrightness) {
+ updateAutoBrightness(false);
+ }
}
private void handleLightSensorEvent(long time, float lux) {
@@ -818,24 +879,83 @@
return;
}
- final int newScreenAutoBrightness = interpolateBrightness(
- mScreenAutoBrightnessSpline, mLightMeasurement);
+ float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
+ float gamma = 1.0f;
+
+ if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
+ && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
+ final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
+ Math.min(1.0f, Math.max(-1.0f,
+ -mPowerRequest.screenAutoBrightnessAdjustment)));
+ gamma *= adjGamma;
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
+ }
+ }
+
+ if (USE_TWILIGHT_ADJUSTMENT) {
+ TwilightState state = mTwilight.getCurrentState();
+ if (state != null && state.isNight()) {
+ final long now = System.currentTimeMillis();
+ final float earlyGamma =
+ getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
+ final float lateGamma =
+ getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
+ gamma *= earlyGamma * lateGamma;
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
+ + ", lateGamma=" + lateGamma);
+ }
+ }
+ }
+
+ if (gamma != 1.0f) {
+ final float in = value;
+ value = FloatMath.pow(value, gamma);
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
+ + ", in=" + in + ", out=" + value);
+ }
+ }
+
+ int newScreenAutoBrightness = clampScreenBrightness(
+ (int)Math.round(value * PowerManager.BRIGHTNESS_ON));
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
- + mScreenAutoBrightness + "newScreenAutoBrightness="
+ + mScreenAutoBrightness + ", newScreenAutoBrightness="
+ newScreenAutoBrightness);
}
mScreenAutoBrightness = newScreenAutoBrightness;
+ mLastScreenAutoBrightnessGamma = gamma;
if (sendUpdate) {
sendUpdatePowerState();
}
}
}
- private static int interpolateBrightness(Spline spline, float lux) {
- return Math.min(255, Math.max(0, (int)Math.round(spline.interpolate(lux))));
+ private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
+ if (lastSunset < 0 || nextSunrise < 0
+ || now < lastSunset || now > nextSunrise) {
+ return 1.0f;
+ }
+
+ if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
+ return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
+ (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
+ return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
+ (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
+ }
+
+ private static float lerp(float x, float y, float alpha) {
+ return x + (y - x) * alpha;
}
private void sendOnStateChanged() {
@@ -943,6 +1063,8 @@
+ TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
+ pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
+ pw.println(" mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
if (mElectronBeamOnAnimator != null) {
pw.println(" mElectronBeamOnAnimator.isStarted()=" +
@@ -990,7 +1112,7 @@
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
- super(looper);
+ super(looper, null, true /*async*/);
}
@Override
@@ -1043,4 +1165,13 @@
// Not used.
}
};
+
+ private final TwilightService.TwilightListener mTwilightListener =
+ new TwilightService.TwilightListener() {
+ @Override
+ public void onTwilightStateChanged() {
+ mTwilightChanged = true;
+ updatePowerState();
+ }
+ };
}
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 7e4607e..2d74292 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -46,6 +46,9 @@
// value to use while waiting for the light sensor to report enough data.
public int screenBrightness;
+ // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter).
+ public float screenAutoBrightnessAdjustment;
+
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
@@ -53,6 +56,7 @@
screenState = SCREEN_STATE_BRIGHT;
useProximitySensor = false;
screenBrightness = PowerManager.BRIGHTNESS_ON;
+ screenAutoBrightnessAdjustment = 0.0f;
useAutoBrightness = false;
}
@@ -64,6 +68,7 @@
screenState = other.screenState;
useProximitySensor = other.useProximitySensor;
screenBrightness = other.screenBrightness;
+ screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
useAutoBrightness = other.useAutoBrightness;
}
@@ -78,6 +83,7 @@
&& screenState == other.screenState
&& useProximitySensor == other.useProximitySensor
&& screenBrightness == other.screenBrightness
+ && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
&& useAutoBrightness == other.useAutoBrightness;
}
@@ -91,6 +97,7 @@
return "screenState=" + screenState
+ ", useProximitySensor=" + useProximitySensor
+ ", screenBrightness=" + screenBrightness
+ + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+ ", useAutoBrightness=" + useAutoBrightness;
}
}
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index 64a0462..3524a08 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -49,8 +49,6 @@
private static final int DIRTY_ELECTRON_BEAM = 1 << 1;
private static final int DIRTY_BRIGHTNESS = 1 << 2;
- private static final int DIRTY_ALL = 0xffffffff;
-
private final Choreographer mChoreographer;
private final ElectronBeam mElectronBeam;
private final PhotonicModulator mScreenBrightnessModulator;
@@ -68,10 +66,16 @@
mElectronBeam = electronBean;
mScreenBrightnessModulator = screenBrightnessModulator;
+ // At boot time, we know that the screen is on and the electron beam
+ // animation is not playing. We don't know the screen's brightness though,
+ // so prepare to set it to a known state when the state is next applied.
+ // Although we set the brightness to full on here, the display power controller
+ // will reset the brightness to a new level immediately before the changes
+ // actually have a chance to be applied.
mScreenOn = true;
mElectronBeamLevel = 1.0f;
mScreenBrightness = PowerManager.BRIGHTNESS_ON;
- invalidate(DIRTY_ALL);
+ invalidate(DIRTY_BRIGHTNESS);
}
public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 2d24249..aad5a9a 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -60,7 +60,7 @@
// The relative proportion of the animation to spend performing
// the horizontal stretch effect. The remainder is spent performing
// the vertical stretch effect.
- private static final float HSTRETCH_DURATION = 0.3f;
+ private static final float HSTRETCH_DURATION = 0.4f;
private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
// Set to true when the animation context has been fully prepared.
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index 37384d2..75f8445 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -28,7 +28,6 @@
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -117,19 +116,15 @@
+ ", workSource=" + workSource);
}
- if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
- try {
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (workSource != null) {
- mBatteryStats.noteStartWakelockFromSource(
- workSource, ownerPid, tag, monitorType);
- } else {
- mBatteryStats.noteStartWakelock(
- ownerUid, ownerPid, tag, monitorType);
- }
- } catch (RemoteException ex) {
- // Ignore
+ try {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (workSource != null) {
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+ } else {
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
}
+ } catch (RemoteException ex) {
+ // Ignore
}
}
@@ -144,30 +139,18 @@
+ ", workSource=" + workSource);
}
- if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
- try {
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (workSource != null) {
- mBatteryStats.noteStopWakelockFromSource(
- workSource, ownerPid, tag, monitorType);
- } else {
- mBatteryStats.noteStopWakelock(
- ownerUid, ownerPid, tag, monitorType);
- }
- } catch (RemoteException ex) {
- // Ignore
+ try {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (workSource != null) {
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
}
+ } catch (RemoteException ex) {
+ // Ignore
}
}
- private static boolean isWakeLockAlreadyReportedToBatteryStats(String tag, int uid) {
- // The window manager already takes care of reporting battery stats associated
- // with the use of the KEEP_SCREEN_ON_FLAG.
- // TODO: Use a WorkSource to handle this situation instead of hardcoding it here.
- return uid == Process.SYSTEM_UID
- && tag.equals(PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
- }
-
private static int getBatteryStatsWakeLockMonitorType(int flags) {
switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
@@ -439,7 +422,7 @@
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
- super(looper);
+ super(looper, null, true /*async*/);
}
@Override
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 2d91e6c..6d68104 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -20,6 +20,7 @@
import com.android.server.BatteryService;
import com.android.server.EventLogTags;
import com.android.server.LightsService;
+import com.android.server.TwilightService;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.display.DisplayManagerService;
@@ -226,6 +227,9 @@
// True if dreams are enabled by the user.
private boolean mDreamsEnabledSetting;
+ // True if dreams should be activated on sleep.
+ private boolean mDreamsActivateOnSleepSetting;
+
// The screen off timeout setting value in milliseconds.
private int mScreenOffTimeoutSetting;
@@ -249,6 +253,10 @@
// Use -1 if no value has been set.
private int mScreenBrightnessSetting;
+ // The screen auto-brightness adjustment setting, from -1 to 1.
+ // Use 0 if there is no adjustment.
+ private float mScreenAutoBrightnessAdjustmentSetting;
+
// The screen brightness mode.
// One of the Settings.System.SCREEN_BRIGHTNESS_MODE_* constants.
private int mScreenBrightnessModeSetting;
@@ -263,6 +271,12 @@
// Use -1 to disable.
private int mTemporaryScreenBrightnessSettingOverride = -1;
+ // The screen brightness adjustment setting override from the settings
+ // application to temporarily adjust the auto-brightness adjustment factor
+ // until next updated, in the range -1..1.
+ // Use NaN to disable.
+ private float mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
+
private native void nativeInit();
private static native void nativeShutdown();
private static native void nativeReboot(String reason) throws IOException;
@@ -282,6 +296,7 @@
}
nativeInit();
+ nativeSetPowerState(true, true);
}
/**
@@ -291,6 +306,14 @@
public void init(Context context, LightsService ls,
ActivityManagerService am, BatteryService bs, IBatteryStats bss,
DisplayManagerService dm) {
+ // Forcibly turn the screen on at boot so that it is in a known power state.
+ // We do this in init() rather than in the constructor because setting the
+ // screen state requires a call into surface flinger which then needs to call back
+ // into the activity manager to check permissions. Unfortunately the
+ // activity manager is not running when the constructor is called, so we
+ // have to defer setting the screen state until this point.
+ nativeSetScreenState(true);
+
mContext = context;
mLightsService = ls;
mBatteryService = bs;
@@ -308,7 +331,7 @@
}
}
- public void systemReady() {
+ public void systemReady(TwilightService twilight) {
synchronized (mLock) {
mSystemReady = true;
@@ -321,7 +344,7 @@
createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy, mScreenOnListener);
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
- mContext, mNotifier, mLightsService,
+ mContext, mNotifier, mLightsService, twilight,
createSuspendBlockerLocked("PowerManagerService.Display"),
mDisplayPowerControllerCallbacks, mHandler);
@@ -345,6 +368,8 @@
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver);
resolver.registerContentObserver(Settings.System.getUriFor(
@@ -376,6 +401,8 @@
mDreamsEnabledSetting = (Settings.Secure.getInt(resolver,
Settings.Secure.SCREENSAVER_ENABLED, 0) != 0);
+ mDreamsActivateOnSleepSetting = (Settings.Secure.getInt(resolver,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0) != 0);
mScreenOffTimeoutSetting = Settings.System.getInt(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
mStayOnWhilePluggedInSetting = Settings.System.getInt(resolver,
@@ -389,6 +416,14 @@
mTemporaryScreenBrightnessSettingOverride = -1;
}
+ final float oldScreenAutoBrightnessAdjustmentSetting =
+ mScreenAutoBrightnessAdjustmentSetting;
+ mScreenAutoBrightnessAdjustmentSetting = Settings.System.getFloat(resolver,
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f);
+ if (oldScreenAutoBrightnessAdjustmentSetting != mScreenAutoBrightnessAdjustmentSetting) {
+ mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
+ }
+
mScreenBrightnessModeSetting = Settings.System.getInt(resolver,
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
@@ -1111,7 +1146,7 @@
*/
private void updateDreamLocked(int dirty) {
if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_SETTINGS
- | DIRTY_IS_POWERED | DIRTY_STAY_ON)) != 0) {
+ | DIRTY_IS_POWERED | DIRTY_STAY_ON | DIRTY_BATTERY_STATE)) != 0) {
scheduleSandmanLocked();
}
}
@@ -1137,13 +1172,13 @@
boolean startDreaming = false;
synchronized (mLock) {
mSandmanScheduled = false;
-
+ boolean canDream = canDreamLocked();
if (DEBUG_SPEW) {
- Log.d(TAG, "handleSandman: canDream=" + canDreamLocked()
+ Log.d(TAG, "handleSandman: canDream=" + canDream
+ ", mWakefulness=" + wakefulnessToString(mWakefulness));
}
- if (canDreamLocked() && mWakefulness == WAKEFULNESS_NAPPING) {
+ if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
startDreaming = true;
}
}
@@ -1227,7 +1262,11 @@
* assuming there has been no recent user activity and no wake locks are held.
*/
private boolean canDreamLocked() {
- return mIsPowered && mDreamsSupportedConfig && mDreamsEnabledSetting;
+ return mIsPowered
+ && mDreamsSupportedConfig
+ && mDreamsEnabledSetting
+ && mDreamsActivateOnSleepSetting
+ && !mBatteryService.isBatteryLow();
}
/**
@@ -1275,6 +1314,7 @@
}
int screenBrightness = mScreenBrightnessSettingDefault;
+ float screenAutoBrightnessAdjustment = 0.0f;
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
@@ -1283,14 +1323,26 @@
} else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
screenBrightness = mTemporaryScreenBrightnessSettingOverride;
} else if (isValidBrightness(mScreenBrightnessSetting)) {
- screenBrightness = mScreenBrightnessSetting;
+ screenBrightness = mScreenBrightnessSetting;
}
if (autoBrightness) {
screenBrightness = mScreenBrightnessSettingDefault;
+ if (isValidAutoBrightnessAdjustment(
+ mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
+ screenAutoBrightnessAdjustment =
+ mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
+ } else if (isValidAutoBrightnessAdjustment(
+ mScreenAutoBrightnessAdjustmentSetting)) {
+ screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
+ }
}
screenBrightness = Math.max(Math.min(screenBrightness,
mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
+ screenAutoBrightnessAdjustment = Math.max(Math.min(
+ screenAutoBrightnessAdjustment, 1.0f), -1.0f);
mDisplayPowerRequest.screenBrightness = screenBrightness;
+ mDisplayPowerRequest.screenAutoBrightnessAdjustment =
+ screenAutoBrightnessAdjustment;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
@@ -1314,6 +1366,11 @@
return value >= 0 && value <= 255;
}
+ private static boolean isValidAutoBrightnessAdjustment(float value) {
+ // Handles NaN by always returning false.
+ return value >= -1.0f && value <= 1.0f;
+ }
+
private int getDesiredScreenPowerState() {
if (mWakefulness == WAKEFULNESS_ASLEEP) {
return DisplayPowerRequest.SCREEN_STATE_OFF;
@@ -1690,15 +1747,32 @@
*
* The override will be canceled when the setting value is next updated.
*
- * @param adj The overridden brightness, or -1 to disable the override.
+ * @param adj The overridden brightness, or Float.NaN to disable the override.
*
* @see Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ
*/
@Override // Binder call
public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) {
- // Not implemented.
- // The SCREEN_AUTO_BRIGHTNESS_ADJ setting is not currently supported.
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float adj) {
+ synchronized (mLock) {
+ // Note: This condition handles NaN because NaN is not equal to any other
+ // value, including itself.
+ if (mTemporaryScreenAutoBrightnessAdjustmentSettingOverride != adj) {
+ mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = adj;
+ mDirty |= DIRTY_SETTINGS;
+ updatePowerStateLocked();
+ }
+ }
}
/**
@@ -1768,17 +1842,22 @@
pw.println("Settings and Configuration:");
pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
+ pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting);
pw.println(" mMaximumScreenOffTimeoutFromDeviceAdmin="
+ mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
+ isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")");
pw.println(" mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
pw.println(" mScreenBrightnessSetting=" + mScreenBrightnessSetting);
+ pw.println(" mScreenAutoBrightnessAdjustmentSetting="
+ + mScreenAutoBrightnessAdjustmentSetting);
pw.println(" mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting);
pw.println(" mScreenBrightnessOverrideFromWindowManager="
+ mScreenBrightnessOverrideFromWindowManager);
pw.println(" mTemporaryScreenBrightnessSettingOverride="
+ mTemporaryScreenBrightnessSettingOverride);
+ pw.println(" mTemporaryScreenAutoBrightnessAdjustmentSettingOverride="
+ + mTemporaryScreenAutoBrightnessAdjustmentSettingOverride);
pw.println(" mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
pw.println(" mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum);
pw.println(" mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault);
@@ -1882,7 +1961,7 @@
*/
private final class PowerManagerHandler extends Handler {
public PowerManagerHandler(Looper looper) {
- super(looper);
+ super(looper, null, true /*async*/);
}
@Override
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index b98ab00..64d2602 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -22,7 +22,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.Slog;
-import android.view.Display;
import android.view.Surface;
import android.view.SurfaceSession;
@@ -36,7 +35,7 @@
final int layer;
final Surface surface;
- BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b)
+ BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b, int layerStack)
throws Surface.OutOfResourcesException {
left = l;
top = t;
@@ -45,10 +44,10 @@
int h = b-t;
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
surface = new WindowStateAnimator.SurfaceTrace(session, 0, "BlackSurface("
- + l + ", " + t + ")", Display.DEFAULT_DISPLAY,
+ + l + ", " + t + ")", layerStack,
w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
} else {
- surface = new Surface(session, 0, "BlackSurface", Display.DEFAULT_DISPLAY,
+ surface = new Surface(session, 0, "BlackSurface", layerStack,
w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
}
surface.setAlpha(1);
@@ -104,7 +103,7 @@
}
public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
- int layer) throws Surface.OutOfResourcesException {
+ int layer, final int layerStack) throws Surface.OutOfResourcesException {
boolean success = false;
mOuterRect = new Rect(outer);
@@ -112,19 +111,19 @@
try {
if (outer.top < inner.top) {
mBlackSurfaces[0] = new BlackSurface(session, layer,
- outer.left, outer.top, inner.right, inner.top);
+ outer.left, outer.top, inner.right, inner.top, layerStack);
}
if (outer.left < inner.left) {
mBlackSurfaces[1] = new BlackSurface(session, layer,
- outer.left, inner.top, inner.left, outer.bottom);
+ outer.left, inner.top, inner.left, outer.bottom, layerStack);
}
if (outer.bottom > inner.bottom) {
mBlackSurfaces[2] = new BlackSurface(session, layer,
- inner.left, inner.bottom, outer.right, outer.bottom);
+ inner.left, inner.bottom, outer.right, outer.bottom, layerStack);
}
if (outer.right > inner.right) {
mBlackSurfaces[3] = new BlackSurface(session, layer,
- inner.right, outer.top, outer.right, inner.bottom);
+ inner.right, outer.top, outer.right, inner.bottom, layerStack);
}
success = true;
} finally {
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 7e8b0ec..81daac6 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -39,18 +39,18 @@
int mLastDimWidth, mLastDimHeight;
- DimAnimator (SurfaceSession session, final int displayId) {
+ DimAnimator (SurfaceSession session, final int layerStack) {
if (mDimSurface == null) {
try {
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
mDimSurface = new WindowStateAnimator.SurfaceTrace(session, 0,
"DimAnimator",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
} else {
mDimSurface = new Surface(session, 0,
"DimAnimator",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
}
if (WindowManagerService.SHOW_TRANSACTIONS ||
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index 0e5d5563..4ab8ce1 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -30,18 +30,18 @@
int mLayer = -1;
int mLastDimWidth, mLastDimHeight;
- DimSurface(SurfaceSession session, final int displayId) {
+ DimSurface(SurfaceSession session, final int layerStack) {
if (mDimSurface == null) {
try {
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
mDimSurface = new WindowStateAnimator.SurfaceTrace(session, 0,
"DimSurface",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
} else {
mDimSurface = new Surface(session, 0,
"DimSurface",
- displayId, 16, 16, PixelFormat.OPAQUE,
+ layerStack, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
}
if (WindowManagerService.SHOW_TRANSACTIONS ||
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index a8854cf..6e5bbcb 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,10 +16,9 @@
package com.android.server.wm;
+import android.view.Display;
import android.view.DisplayInfo;
-import com.android.server.display.DisplayManagerService;
-
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -60,13 +59,13 @@
int mBaseDisplayWidth = 0;
int mBaseDisplayHeight = 0;
int mBaseDisplayDensity = 0;
- final DisplayManagerService mDisplayManager;
final DisplayInfo mDisplayInfo = new DisplayInfo();
+ final Display mDisplay;
- DisplayContent(DisplayManagerService displayManager, final int displayId) {
- mDisplayManager = displayManager;
- mDisplayId = displayId;
- displayManager.getDisplayInfo(displayId, mDisplayInfo);
+ DisplayContent(Display display) {
+ mDisplay = display;
+ mDisplayId = display.getDisplayId();
+ display.getDisplayInfo(mDisplayInfo);
}
int getDisplayId() {
@@ -77,6 +76,10 @@
return mWindows;
}
+ Display getDisplay() {
+ return mDisplay;
+ }
+
DisplayInfo getDisplayInfo() {
return mDisplayInfo;
}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 26ea7c1..3fcf680 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -71,12 +71,6 @@
mFlags = flags;
mLocalWin = localWin;
mNotifiedWindows = new ArrayList<WindowState>();
- WindowState win = service.mWindowMap.get(token);
- if (win != null) {
- mDisplayContent = win.mDisplayContent;
- } else {
- Slog.e(WindowManagerService.TAG, "No window associated with token");
- }
}
void reset() {
@@ -92,7 +86,11 @@
mNotifiedWindows = null;
}
- void register() {
+ /**
+ * @param displayContent The display parameters associated with the window being dragged.
+ */
+ void register(DisplayContent displayContent) {
+ mDisplayContent = displayContent;
if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "registering drag input channel");
if (mClientChannel != null) {
Slog.e(WindowManagerService.TAG, "Duplicate register of drag input channel");
diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/java/com/android/server/wm/KeyguardDisableHandler.java
new file mode 100644
index 0000000..d935b8b
--- /dev/null
+++ b/services/java/com/android/server/wm/KeyguardDisableHandler.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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 com.android.server.wm;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.TokenWatcher;
+import android.util.Log;
+import android.util.Pair;
+import android.view.WindowManagerPolicy;
+
+public class KeyguardDisableHandler extends Handler {
+ private static final String TAG = "KeyguardDisableHandler";
+
+ private static final int ALLOW_DISABLE_YES = 1;
+ private static final int ALLOW_DISABLE_NO = 0;
+ private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
+ private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher
+
+ // Message.what constants
+ static final int KEYGUARD_DISABLE = 1;
+ static final int KEYGUARD_REENABLE = 2;
+ static final int KEYGUARD_POLICY_CHANGED = 3;
+
+ final Context mContext;
+ final WindowManagerPolicy mPolicy;
+ KeyguardTokenWatcher mKeyguardTokenWatcher;
+
+ public KeyguardDisableHandler(final Context context, final WindowManagerPolicy policy) {
+ mContext = context;
+ mPolicy = policy;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleMessage(Message msg) {
+ if (mKeyguardTokenWatcher == null) {
+ mKeyguardTokenWatcher = new KeyguardTokenWatcher(this);
+ }
+
+ switch (msg.what) {
+ case KEYGUARD_DISABLE:
+ final Pair<IBinder, String> pair = (Pair<IBinder, String>)msg.obj;
+ mKeyguardTokenWatcher.acquire(pair.first, pair.second);
+ break;
+
+ case KEYGUARD_REENABLE:
+ mKeyguardTokenWatcher.release((IBinder)msg.obj);
+ break;
+
+ case KEYGUARD_POLICY_CHANGED:
+ mPolicy.enableKeyguard(true);
+ // lazily evaluate this next time we're asked to disable keyguard
+ mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
+ break;
+ }
+ }
+
+ class KeyguardTokenWatcher extends TokenWatcher {
+
+ public KeyguardTokenWatcher(final Handler handler) {
+ super(handler, TAG);
+ }
+
+ @Override
+ public void acquired() {
+ // We fail safe and prevent disabling keyguard in the unlikely event this gets
+ // called before DevicePolicyManagerService has started.
+ if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {
+ DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ mAllowDisableKeyguard = dpm.getPasswordQuality(null)
+ == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
+ ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+ }
+ }
+ if (mAllowDisableKeyguard == ALLOW_DISABLE_YES) {
+ mPolicy.enableKeyguard(false);
+ } else {
+ Log.v(TAG, "Not disabling keyguard since device policy is enforced");
+ }
+ }
+
+ @Override
+ public void released() {
+ mPolicy.enableKeyguard(true);
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 7d85d89..7679413 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -477,6 +477,7 @@
mRotateFrameAnimation.scaleCurrentDuration(animationScale);
}
+ final int layerStack = mDisplay.getLayerStack();
if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
WindowManagerService.TAG,
@@ -495,7 +496,8 @@
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3);
+ mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3,
+ layerStack);
mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
@@ -525,7 +527,8 @@
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2);
+ mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2,
+ layerStack);
mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
@@ -547,7 +550,8 @@
Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
finalWidth*2, finalHeight*2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
- mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
+ mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER,
+ layerStack);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index d44b170..1ffbecc 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -280,7 +280,7 @@
// !!! FIXME: put all this heavy stuff onto the mH looper, as well as
// the actual drag event dispatch stuff in the dragstate
- mService.mDragState.register();
+ mService.mDragState.register(callingWin.mDisplayContent);
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
mService.mDragState.mServerChannel)) {
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 1defa49..580f00d 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -103,6 +103,8 @@
/** Do not modify unless holding mService.mWindowMap or this and mAnimToLayout in that order */
final AnimatorToLayoutParams mAnimToLayout = new AnimatorToLayoutParams();
+ boolean mInitialized = false;
+
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
@@ -121,10 +123,13 @@
}
}
};
+ }
+ void initializeLocked(final int layerStack) {
mWindowAnimationBackgroundSurface =
- new DimSurface(mService.mFxSession, Display.DEFAULT_DISPLAY);
- mDimAnimator = new DimAnimator(mService.mFxSession, Display.DEFAULT_DISPLAY);
+ new DimSurface(mService.mFxSession, layerStack);
+ mDimAnimator = new DimAnimator(mService.mFxSession, layerStack);
+ mInitialized = true;
}
/** Locked on mAnimToLayout */
@@ -563,6 +568,9 @@
// TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
/** Locked on mService.mWindowMap and this. */
private void animateLocked() {
+ if (!mInitialized) {
+ return;
+ }
for (int i = mWinAnimatorLists.size() - 1; i >= 0; i--) {
animateLocked(mWinAnimatorLists.get(i));
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index fd90082..42bc7ce 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -74,7 +74,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.os.BatteryStats;
+import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -92,8 +92,8 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.TokenWatcher;
import android.os.Trace;
+import android.os.WorkSource;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -277,55 +277,19 @@
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- /**
- * Condition waited on by {@link #reenableKeyguard} to know the call to
- * the window policy has finished.
- * This is set to true only if mKeyguardTokenWatcher.acquired() has
- * actually disabled the keyguard.
- */
- private boolean mKeyguardDisabled = false;
+ final private KeyguardDisableHandler mKeyguardDisableHandler;
private final boolean mHeadless;
- private static final int ALLOW_DISABLE_YES = 1;
- private static final int ALLOW_DISABLE_NO = 0;
- private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
- private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher
-
private static final float THUMBNAIL_ANIMATION_DECELERATE_FACTOR = 1.5f;
- final TokenWatcher mKeyguardTokenWatcher = new TokenWatcher(
- new Handler(), "WindowManagerService.mKeyguardTokenWatcher") {
- @Override
- public void acquired() {
- if (shouldAllowDisableKeyguard()) {
- mPolicy.enableKeyguard(false);
- mKeyguardDisabled = true;
- } else {
- Log.v(TAG, "Not disabling keyguard since device policy is enforced");
- }
- }
- @Override
- public void released() {
- mPolicy.enableKeyguard(true);
- synchronized (mKeyguardTokenWatcher) {
- mKeyguardDisabled = false;
- mKeyguardTokenWatcher.notifyAll();
- }
- }
- };
-
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
- mPolicy.enableKeyguard(true);
- synchronized(mKeyguardTokenWatcher) {
- // lazily evaluate this next time we're asked to disable keyguard
- mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
- mKeyguardDisabled = false;
- }
+ mKeyguardDisableHandler.sendEmptyMessage(
+ KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Slog.v(TAG, "Switching user from " + mCurrentUserId + " to " + newUserId);
@@ -539,7 +503,7 @@
final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
- Display mDisplay;
+ Display mDefaultDisplay;
boolean mIsTouchDevice;
@@ -605,7 +569,8 @@
float mAnimatorDurationScale = 1.0f;
final InputManagerService mInputManager;
- final DisplayManagerService mDisplayManager;
+ final DisplayManagerService mDisplayManagerService;
+ final DisplayManager mDisplayManager;
// Who is holding the screen on.
Session mHoldingScreenOn;
@@ -843,17 +808,14 @@
private final WindowManagerPolicy mPolicy;
private final WindowManagerService mService;
private final Context mContext;
- private final PowerManagerService mPM;
boolean mRunning = false;
public PolicyThread(WindowManagerPolicy policy,
- WindowManagerService service, Context context,
- PowerManagerService pm) {
+ WindowManagerService service, Context context) {
super("WindowManagerPolicy");
mPolicy = policy;
mService = service;
mContext = context;
- mPM = pm;
}
@Override
@@ -894,9 +856,12 @@
mOnlyCore = onlyCore;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
- mDisplayManager = displayManager;
+ mDisplayManagerService = displayManager;
+ mDisplayManager = DisplayManager.getInstance();
mHeadless = displayManager.isHeadless();
+ mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
+
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -923,14 +888,14 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ON_AFTER_RELEASE, PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
+ | PowerManager.ON_AFTER_RELEASE, TAG);
mHoldingScreenWakeLock.setReferenceCounted(false);
mInputManager = new InputManagerService(context, mInputMonitor);
mFxSession = new SurfaceSession();
mAnimator = new WindowAnimator(this);
- PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
+ PolicyThread thr = new PolicyThread(mPolicy, this, context);
thr.start();
synchronized (thr) {
@@ -1237,7 +1202,6 @@
/**
* Dig through the WindowStates and find the one that the Input Method will target.
* @param willMove
- * @param windows TODO(cmautner):
* @return The index+1 in mWindows of the discovered target.
*/
int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
@@ -2163,7 +2127,7 @@
long origId;
synchronized(mWindowMap) {
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
throw new IllegalStateException("Display has not been initialialized");
}
@@ -3075,6 +3039,7 @@
Binder.restoreCallingIdentity(origId);
}
+ @Override
public float getWindowCompatibilityScale(IBinder windowToken) {
if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
"getWindowCompatibilityScale()")) {
@@ -3806,7 +3771,7 @@
Configuration config = null;
long ident = Binder.clearCallingIdentity();
-
+
synchronized(mWindowMap) {
config = updateOrientationFromAppTokensLocked(currentConfig,
freezeThisOneIfNeeded);
@@ -3847,7 +3812,7 @@
}
}
}
-
+
return config;
}
@@ -3858,7 +3823,7 @@
* setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
* SCREEN. This will typically be done for you if you call
* sendNewConfiguration().
- *
+ *
* The orientation is computed from non-application windows first. If none of
* the non-application windows specify orientation, the orientation is computed from
* application tokens.
@@ -5061,59 +5026,26 @@
// Misc IWindowSession methods
// -------------------------------------------------------------
- private boolean shouldAllowDisableKeyguard()
- {
- // We fail safe and prevent disabling keyguard in the unlikely event this gets
- // called before DevicePolicyManagerService has started.
- if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {
- DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- mAllowDisableKeyguard = dpm.getPasswordQuality(null)
- == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
- ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
- }
- }
- return mAllowDisableKeyguard == ALLOW_DISABLE_YES;
- }
-
+ @Override
public void disableKeyguard(IBinder token, String tag) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- synchronized (mKeyguardTokenWatcher) {
- mKeyguardTokenWatcher.acquire(token, tag);
- }
+ mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
+ KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
}
+ @Override
public void reenableKeyguard(IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- synchronized (mKeyguardTokenWatcher) {
- mKeyguardTokenWatcher.release(token);
-
- if (!mKeyguardTokenWatcher.isAcquired()) {
- // If we are the last one to reenable the keyguard wait until
- // we have actually finished reenabling until returning.
- // It is possible that reenableKeyguard() can be called before
- // the previous disableKeyguard() is handled, in which case
- // neither mKeyguardTokenWatcher.acquired() or released() would
- // be called. In that case mKeyguardDisabled will be false here
- // and we have nothing to wait for.
- while (mKeyguardDisabled) {
- try {
- mKeyguardTokenWatcher.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
+ mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
+ KeyguardDisableHandler.KEYGUARD_REENABLE, token));
}
/**
@@ -5545,7 +5477,7 @@
Surface.openTransaction();
try {
if (mStrictModeFlash == null) {
- mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession);
+ mStrictModeFlash = new StrictModeFlash(mDefaultDisplay, mFxSession);
}
mStrictModeFlash.setVisibility(on);
} finally {
@@ -5658,7 +5590,7 @@
}
// The screenshot API does not apply the current screen rotation.
- rot = mDisplay.getRotation();
+ rot = mDefaultDisplay.getRotation();
int fw = frame.width();
int fh = frame.height();
@@ -6573,7 +6505,7 @@
}
boolean computeScreenConfigurationLocked(Configuration config) {
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
return false;
}
@@ -6629,7 +6561,7 @@
displayInfo.appHeight = appHeight;
displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
displayInfo.getAppMetrics(mDisplayMetrics, null);
- mDisplayManager.setDisplayInfo(displayContent.getDisplayId(), displayInfo);
+ mDisplayManagerService.setDisplayInfo(displayContent.getDisplayId(), displayInfo);
mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight);
}
@@ -6780,7 +6712,7 @@
try {
if (mDragState == null) {
Surface surface = new Surface(session, callerPid, "drag surface",
- Display.DEFAULT_DISPLAY,
+ mDefaultDisplay.getLayerStack(),
width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
if (SHOW_TRANSACTIONS) Slog.i(TAG, " DRAG "
+ surface + ": CREATE");
@@ -6938,30 +6870,33 @@
}
public void displayReady() {
- displayReady(Display.DEFAULT_DISPLAY);
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ final Display display = wm.getDefaultDisplay();
+ displayReady(display.getDisplayId());
synchronized(mWindowMap) {
readForcedDisplaySizeAndDensityLocked(getDefaultDisplayContent());
- WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- mDisplay = wm.getDefaultDisplay();
+ mDefaultDisplay = display;
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
+ mAnimator.initializeLocked(display.getLayerStack());
+
final DisplayInfo displayInfo = getDefaultDisplayInfo();
mAnimator.setDisplayDimensions(displayInfo.logicalWidth, displayInfo.logicalHeight,
displayInfo.appWidth, displayInfo.appHeight);
DisplayDeviceInfo info = new DisplayDeviceInfo();
- mDisplayManager.getDefaultExternalDisplayDeviceInfo(info);
+ mDisplayManagerService.getDefaultExternalDisplayDeviceInfo(info);
final DisplayContent displayContent = getDefaultDisplayContent();
- mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
+ mInputManager.setDisplaySize(displayContent.getDisplayId(),
displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight,
info.width, info.height);
- mInputManager.setDisplayOrientation(Display.DEFAULT_DISPLAY,
- mDisplay.getRotation(), Surface.ROTATION_0);
- mPolicy.setInitialDisplaySize(mDisplay, displayContent.mInitialDisplayWidth,
+ mInputManager.setDisplayOrientation(displayContent.getDisplayId(),
+ mDefaultDisplay.getRotation(), Surface.ROTATION_0);
+ mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mInitialDisplayWidth,
displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
}
@@ -6978,7 +6913,7 @@
synchronized(displayContent.mDisplaySizeLock) {
// Bootstrap the default logical display from the display manager.
displayInfo = displayContent.getDisplayInfo();
- mDisplayManager.getDisplayInfo(displayId, displayInfo);
+ mDisplayManagerService.getDisplayInfo(displayId, displayInfo);
displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
@@ -7020,7 +6955,7 @@
public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
public static final int WINDOW_FREEZE_TIMEOUT = 11;
- public static final int HOLD_SCREEN_CHANGED = 12;
+
public static final int APP_TRANSITION_TIMEOUT = 13;
public static final int PERSIST_ANIMATION_SCALE = 14;
public static final int FORCE_GC = 15;
@@ -7041,8 +6976,6 @@
public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
- private Session mLastReportedHold;
-
public H() {
}
@@ -7294,33 +7227,6 @@
break;
}
- case HOLD_SCREEN_CHANGED: {
- Session oldHold;
- Session newHold;
- synchronized (mWindowMap) {
- oldHold = mLastReportedHold;
- newHold = (Session)msg.obj;
- mLastReportedHold = newHold;
- }
-
- if (oldHold != newHold) {
- try {
- if (oldHold != null) {
- mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
- "window",
- BatteryStats.WAKE_TYPE_WINDOW);
- }
- if (newHold != null) {
- mBatteryStats.noteStartWakelock(newHold.mUid, -1,
- "window",
- BatteryStats.WAKE_TYPE_WINDOW);
- }
- } catch (RemoteException e) {
- }
- }
- break;
- }
-
case APP_TRANSITION_TIMEOUT: {
synchronized (mWindowMap) {
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -7648,7 +7554,8 @@
Rect outer = new Rect(0, 0, initW, initH);
Rect inner = new Rect(0, 0, baseW, baseH);
try {
- mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
+ mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER,
+ mDefaultDisplay.getLayerStack());
} catch (Surface.OutOfResourcesException e) {
}
}
@@ -7747,7 +7654,7 @@
}
private void reconfigureDisplayLocked(DisplayContent displayContent) {
- mPolicy.setInitialDisplaySize(mDisplay, displayContent.mBaseDisplayWidth,
+ mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mBaseDisplayWidth,
displayContent.mBaseDisplayHeight, displayContent.mBaseDisplayDensity);
mLayoutNeeded = true;
@@ -7972,7 +7879,7 @@
return;
}
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
// Not yet initialized, nothing to do.
return;
}
@@ -8436,7 +8343,7 @@
mNextAppTransitionThumbnail.getHeight());
try {
Surface surface = new Surface(mFxSession, Process.myPid(),
- "thumbnail anim", Display.DEFAULT_DISPLAY,
+ "thumbnail anim", mDefaultDisplay.getLayerStack(),
dirty.width(), dirty.height(),
PixelFormat.TRANSLUCENT, Surface.HIDDEN);
topOpeningApp.mAppAnimator.thumbnail = surface;
@@ -8704,7 +8611,7 @@
Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
+ Debug.getCallers(3));
}
- if (mDisplay == null) {
+ if (mDefaultDisplay == null) {
Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
return;
}
@@ -9134,7 +9041,7 @@
// Finally update all input windows now that the window changes have stabilized.
mInputMonitor.updateInputWindowsLw(true /*force*/);
- setHoldScreenLocked(mInnerFields.mHoldScreen != null);
+ setHoldScreenLocked(mInnerFields.mHoldScreen);
if (!mDisplayFrozen) {
if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
@@ -9149,11 +9056,6 @@
toBrightnessOverride(mInnerFields.mButtonBrightness));
}
}
- if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
- mHoldingScreenOn = mInnerFields.mHoldScreen;
- Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
- mH.sendMessage(m);
- }
if (mTurnOnScreen) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
@@ -9237,13 +9139,17 @@
}
}
- /**
- * Must be called with the main window manager lock held.
- */
- void setHoldScreenLocked(boolean holding) {
- boolean state = mHoldingScreenWakeLock.isHeld();
- if (holding != state) {
- if (holding) {
+ void setHoldScreenLocked(final Session newHoldScreen) {
+ final boolean hold = newHoldScreen != null;
+
+ if (hold && mHoldingScreenOn != newHoldScreen) {
+ mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
+ }
+ mHoldingScreenOn = newHoldScreen;
+
+ final boolean state = mHoldingScreenWakeLock.isHeld();
+ if (hold != state) {
+ if (hold) {
mPolicy.screenOnStartedLw();
mHoldingScreenWakeLock.acquire();
} else {
@@ -9616,7 +9522,7 @@
return;
}
- if (mDisplay == null || !mPolicy.isScreenOnFully()) {
+ if (mDefaultDisplay == null || !mPolicy.isScreenOnFully()) {
// No need to freeze the screen before the system is ready or if
// the screen is off.
return;
@@ -9649,9 +9555,9 @@
// TODO(multidisplay): rotation on main screen only.
DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo();
- mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, mDisplay,
- mFxSession, inTransaction, displayInfo.logicalWidth, displayInfo.logicalHeight,
- mDisplay.getRotation());
+ mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+ mDefaultDisplay, mFxSession, inTransaction, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, mDefaultDisplay.getRotation());
}
}
@@ -9762,7 +9668,8 @@
if (line != null) {
String[] toks = line.split("%");
if (toks != null && toks.length > 0) {
- mWatermark = new Watermark(mDisplay, mRealDisplayMetrics, mFxSession, toks);
+ mWatermark =
+ new Watermark(mDefaultDisplay, mRealDisplayMetrics, mFxSession, toks);
}
}
} catch (FileNotFoundException e) {
@@ -10130,7 +10037,7 @@
}
}
pw.println();
- if (mDisplay != null) {
+ if (mDefaultDisplay != null) {
DisplayContentsIterator dCIterator = new DisplayContentsIterator();
while (dCIterator.hasNext()) {
dCIterator.next().dump(pw);
@@ -10440,7 +10347,6 @@
// Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
public void monitor() {
synchronized (mWindowMap) { }
- synchronized (mKeyguardTokenWatcher) { }
}
public interface OnHardKeyboardStatusChangeListener {
@@ -10457,7 +10363,7 @@
public DisplayContent getDisplayContent(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
- displayContent = new DisplayContent(mDisplayManager, displayId);
+ displayContent = new DisplayContent(mDisplayManager.getRealDisplay(displayId));
mDisplayContents.put(displayId, displayContent);
}
return displayContent;
@@ -10526,7 +10432,8 @@
}
} else {
mWindowListIndex++;
- if (mWindowListIndex >= mWindowList.size() && mDisplayContentsIterator.hasNext()) {
+ if (mWindowListIndex >= mWindowList.size()
+ && mDisplayContentsIterator.hasNext()) {
mDisplayContent = mDisplayContentsIterator.next();
mWindowList = mDisplayContent.getWindowList();
mWindowListIndex = 0;
@@ -10544,7 +10451,9 @@
}
public DisplayContent getDefaultDisplayContent() {
- return getDisplayContent(Display.DEFAULT_DISPLAY);
+ final int displayId = mDefaultDisplay == null
+ ? Display.DEFAULT_DISPLAY : mDefaultDisplay.getDisplayId();
+ return getDisplayContent(displayId);
}
public WindowList getDefaultWindowList() {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index ae641a3..a52e1d7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -36,6 +36,7 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
@@ -261,8 +262,8 @@
DisplayContent mDisplayContent;
- // UserId of the owner. Don't display windows of non-current user.
- final int mOwnerUserId;
+ // UserId and appId of the owner. Don't display windows of non-current user.
+ final int mOwnerUid;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
@@ -271,7 +272,7 @@
mSession = s;
mClient = c;
mToken = token;
- mOwnerUserId = UserHandle.getUserId(s.mUid);
+ mOwnerUid = s.mUid;
mAttrs.copyFrom(a);
mViewVisibility = viewVisibility;
mDisplayContent = displayContent;
@@ -904,7 +905,7 @@
boolean showLw(boolean doAnimation, boolean requestAnim) {
if (isOtherUsersAppWindow()) {
Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
- + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUserId);
+ + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
return false;
}
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
@@ -985,9 +986,10 @@
boolean isOtherUsersAppWindow() {
final int type = mAttrs.type;
- if ((mOwnerUserId != mService.mCurrentUserId)
+ if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId)
+ && (mOwnerUid != Process.SYSTEM_UID)
&& (type >= TYPE_BASE_APPLICATION) && (type <= LAST_APPLICATION_WINDOW)
- && (type != TYPE_APPLICATION_STARTING)) {
+ && (type != TYPE_APPLICATION_STARTING)) {
return true;
}
return false;
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 93c0203..982f60d 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -148,6 +148,8 @@
int mAttrFlags;
int mAttrType;
+ final int mLayerStack;
+
public WindowStateAnimator(final WindowState win) {
final WindowManagerService service = win.mService;
@@ -167,6 +169,7 @@
mAttrFlags = win.mAttrs.flags;
mAttrType = win.mAttrs.type;
mIsWallpaper = win.mIsWallpaper;
+ mLayerStack = win.mDisplayContent.getDisplay().getLayerStack();
}
public void setAnimation(Animation anim) {
@@ -651,12 +654,12 @@
mSurface = new SurfaceTrace(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
- mWin.mDisplayContent.getDisplayId(), w, h, format, flags);
+ mLayerStack, w, h, format, flags);
} else {
mSurface = new Surface(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
- mWin.mDisplayContent.getDisplayId(), w, h, format, flags);
+ mLayerStack, w, h, format, flags);
}
mWin.mHasSurface = true;
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
@@ -1292,7 +1295,7 @@
boolean performShowLocked() {
if (mWin.isOtherUsersAppWindow()) {
Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
- + this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUserId);
+ + this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
return false;
}
if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 89b2474..8aeb2af 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -34,7 +34,8 @@
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
-
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+
<application>
<uses-library android:name="android.test.runner" />
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index 20439bc..4d1eb3f 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -22,6 +22,8 @@
/* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
public static final String INTENT_KEY_ICC_STATE = "ss";
+ /* UNKNOWN means the ICC state is unknown */
+ public static final String INTENT_VALUE_ICC_UNKNOWN = "UNKNOWN";
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
/* ABSENT means ICC is missing */
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 12ad4fea..6047cda 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -360,6 +360,18 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public ComponentName startServiceAsUser(Intent service, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public boolean stopServiceAsUser(Intent service, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 0fb51f0..562f286 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -41,6 +41,7 @@
import android.content.pm.UserInfo;
import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -531,11 +532,26 @@
throw new UnsupportedOperationException();
}
+ /**
+ * @hide
+ */
+ @Override
+ public int installExistingPackage(String packageName)
+ throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void verifyPendingInstall(int id, int verificationCode) {
throw new UnsupportedOperationException();
}
+ @Override
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @hide
*/
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java
index ea8a018..dab8111 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java
@@ -46,7 +46,7 @@
v[0] = 0.f; v[1] = -s; v[2] = 0.f;
v[3] = -s; v[4] = s*4+1; v[5] = -s;
v[6] = 0.f; v[7] = -s; v[8] = 0.f;
- mScript.setValues(v);
+ mScript.setColorMatrix(v);
}
@@ -55,7 +55,8 @@
}
public void runTest() {
- mScript.forEach(mInPixelsAllocation, mOutPixelsAllocation);
+ mScript.setInput(mInPixelsAllocation);
+ mScript.forEach(mOutPixelsAllocation);
}
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs
index 97ae4fb..7d9d3ac 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs
@@ -43,10 +43,10 @@
rs_allocation gBlendSource;
void blend9(uchar *out, uint32_t x, uint32_t y) {
- uint32_t x1 = min(x+1, (uint32_t)gWidth);
- uint32_t x2 = max(x-1, (uint32_t)0);
- uint32_t y1 = min(y+1, (uint32_t)gHeight);
- uint32_t y2 = max(y-1, (uint32_t)0);
+ uint32_t x1 = min((int32_t)x+1, (int32_t)gWidth);
+ uint32_t x2 = max((int32_t)x-1, (int32_t)0);
+ uint32_t y1 = min((int32_t)y+1, (int32_t)gHeight);
+ uint32_t y2 = max((int32_t)y-1, (int32_t)0);
uint p00 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x1, y1))[0];
uint p01 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y1))[0];
diff --git a/tests/RenderScriptTests/ImageProcessing2/Android.mk b/tests/RenderScriptTests/ImageProcessing2/Android.mk
index c81fd93..e05a518 100644
--- a/tests/RenderScriptTests/ImageProcessing2/Android.mk
+++ b/tests/RenderScriptTests/ImageProcessing2/Android.mk
@@ -25,6 +25,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := android.support.v8.renderscript
LOCAL_PACKAGE_NAME := ImageProcessing2
+LOCAL_SDK_VERSION := 8
+LOCAL_RENDERSCRIPT_TARGET_API := 17
+LOCAL_RENDERSCRIPT_INCLUDES_OVERRIDE := $(TOPDIR)external/clang/lib/Headers \
+ $(TOPDIR)frameworks/rs/scriptc
LOCAL_RENDERSCRIPT_FLAGS := -rs-package-name=android.support.v8.renderscript
LOCAL_REQUIRED_MODULES := librsjni
diff --git a/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
index 1ef04c2..20ee053 100644
--- a/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
+++ b/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
@@ -2,9 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.rs.image2">
- <uses-sdk android:minSdkVersion="11" />
- <application android:label="IP GB"
- android:hardwareAccelerated="true">
+ <uses-sdk android:minSdkVersion="8" />
+ <application android:label="IP GB">
<activity android:name="ImageProcessingActivity2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 3d45bff..76033d4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1281,6 +1281,18 @@
}
@Override
+ public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
+ // pass
+ return null;
+ }
+
+ @Override
+ public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
+ // pass
+ return false;
+ }
+
+ @Override
public void unbindService(ServiceConnection arg0) {
// pass
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 1d06c76..a5322fa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -3553,7 +3553,12 @@
handleNetworkDisconnect();
break;
case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
- // EAP failures do not mean much during WPS
+ // Disregard auth failure events during WPS connection. The
+ // EAP sequence is retried several times, and there might be
+ // failures (especially for wps pin). We will get a WPS_XXX
+ // event at the end of the sequence anyway.
+ if (DBG) log("Ignore auth failure during WPS connection");
+ break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
//Throw away supplicant state changes when WPS is running.
//We will start getting supplicant state changes once we get