Merge "ImageReader: fix documentation, relax some guarantees" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index d4f2cc5..a51216e3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -479,6 +479,7 @@
field public static final int dashWidth = 16843174; // 0x10101a6
field public static final int data = 16842798; // 0x101002e
field public static final int datePickerDialogTheme = 16843951; // 0x10104af
+ field public static final int datePickerMode = 16843958; // 0x10104b6
field public static final int datePickerStyle = 16843612; // 0x101035c
field public static final int dateTextAppearance = 16843593; // 0x1010349
field public static final int dayOfWeekBackgroundColor = 16843926; // 0x1010496
@@ -1313,6 +1314,7 @@
field public static final int tileModeX = 16843897; // 0x1010479
field public static final int tileModeY = 16843898; // 0x101047a
field public static final int timePickerDialogTheme = 16843936; // 0x10104a0
+ field public static final int timePickerMode = 16843959; // 0x10104b7
field public static final int timePickerStyle = 16843935; // 0x101049f
field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5684a7a..90b8b86 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -32,7 +32,6 @@
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1900,8 +1899,7 @@
mPriority = PRIORITY_DEFAULT;
mPeople = new ArrayList<String>();
- mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ?
- NotificationColorUtil.getInstance() : null;
+ mColorUtil = NotificationColorUtil.getInstance();
}
/**
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
index 45a066d..d80f58c 100644
--- a/core/java/android/app/trust/ITrustListener.aidl
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -22,6 +22,6 @@
* {@hide}
*/
oneway interface ITrustListener {
- void onTrustChanged(boolean enabled, int userId);
+ void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
void onTrustManagedChanged(boolean managed, int userId);
}
\ No newline at end of file
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 796e3cc..3d262b1 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -34,6 +34,7 @@
private static final int MSG_TRUST_MANAGED_CHANGED = 2;
private static final String TAG = "TrustManager";
+ private static final String DATA_INITIATED_BY_USER = "initiatedByUser";
private final ITrustManager mService;
private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
@@ -95,14 +96,17 @@
try {
ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
@Override
- public void onTrustChanged(boolean enabled, int userId) throws RemoteException {
- mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
- trustListener).sendToTarget();
+ public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
+ Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
+ trustListener);
+ if (initiatedByUser) {
+ m.getData().putBoolean(DATA_INITIATED_BY_USER, initiatedByUser);
+ }
+ m.sendToTarget();
}
@Override
- public void onTrustManagedChanged(boolean managed, int userId)
- throws RemoteException {
+ public void onTrustManagedChanged(boolean managed, int userId) {
mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId,
trustListener).sendToTarget();
}
@@ -139,7 +143,11 @@
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_TRUST_CHANGED:
- ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2);
+ boolean initiatedByUser = msg.peekData() != null &&
+ msg.peekData().getBoolean(DATA_INITIATED_BY_USER);
+ ((TrustListener)msg.obj).onTrustChanged(
+ msg.arg1 != 0, msg.arg2, initiatedByUser);
+
break;
case MSG_TRUST_MANAGED_CHANGED:
((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
@@ -153,8 +161,10 @@
* Reports that the trust state has changed.
* @param enabled if true, the system believes the environment to be trusted.
* @param userId the user, for which the trust changed.
+ * @param initiatedByUser indicates that the user has explicitly initiated an action that
+ * proves the user is about to use the device.
*/
- void onTrustChanged(boolean enabled, int userId);
+ void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
/**
* Reports that whether trust is managed has changed
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 3b026bd..285dee8 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -105,7 +105,17 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
- getContext().registerReceiver(mReceiver, filter);
+
+ // OK, this is gross but needed. This class is supported by the
+ // remote views machanism and as a part of that the remote views
+ // can be inflated by a context for another user without the app
+ // having interact users permission - just for loading resources.
+ // For exmaple, when adding widgets from a user profile to the
+ // home screen. Therefore, we register the receiver as the current
+ // user not the one the context is for.
+ getContext().registerReceiverAsUser(mReceiver, android.os.Process.myUserHandle(),
+ filter, null, mHandler);
+
if (mAutoStart) {
// Automatically start when requested
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 74c66c8..d0a2eab 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -84,6 +84,9 @@
public class DatePicker extends FrameLayout {
private static final String LOG_TAG = DatePicker.class.getSimpleName();
+ private static final int MODE_SPINNER = 1;
+ private static final int MODE_CALENDAR = 2;
+
private final DatePickerDelegate mDelegate;
/**
@@ -120,24 +123,28 @@
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyleAttr, defStyleRes);
- final boolean legacyMode = a.getBoolean(R.styleable.DatePicker_legacyMode, true);
+ int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
a.recycle();
- if (legacyMode) {
- mDelegate = createLegacyUIDelegate(context, attrs, defStyleAttr, defStyleRes);
- } else {
- mDelegate = createNewUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ switch (mode) {
+ case MODE_CALENDAR:
+ mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ break;
+ case MODE_SPINNER:
+ default:
+ mDelegate = createSpinnerUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ break;
}
}
- private DatePickerDelegate createLegacyUIDelegate(Context context, AttributeSet attrs,
+ private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
- return new LegacyDatePickerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
+ return new DatePickerSpinnerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
}
- private DatePickerDelegate createNewUIDelegate(Context context, AttributeSet attrs,
+ private DatePickerDelegate createCalendarUIDelegate(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
- return new android.widget.DatePickerDelegate(this, context, attrs, defStyleAttr,
+ return new DatePickerCalendarDelegate(this, context, attrs, defStyleAttr,
defStyleRes);
}
@@ -454,7 +461,7 @@
/**
* A delegate implementing the basic DatePicker
*/
- private static class LegacyDatePickerDelegate extends AbstractDatePickerDelegate {
+ private static class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
private static final String DATE_FORMAT = "MM/dd/yyyy";
@@ -500,7 +507,7 @@
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
- LegacyDatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+ DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(delegator, context);
diff --git a/core/java/android/widget/DatePickerDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
similarity index 99%
rename from core/java/android/widget/DatePickerDelegate.java
rename to core/java/android/widget/DatePickerCalendarDelegate.java
index ddc565d..c0c76ac 100644
--- a/core/java/android/widget/DatePickerDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -52,7 +52,7 @@
/**
* A delegate for picking up a date (day / month / year).
*/
-class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implements
+class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate implements
View.OnClickListener, DatePickerController {
private static final int UNINITIALIZED = -1;
@@ -113,7 +113,7 @@
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
- public DatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+ public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(delegator, context);
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 026a8ee..c488666 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -45,6 +45,9 @@
*/
@Widget
public class TimePicker extends FrameLayout {
+ private static final int MODE_SPINNER = 1;
+ private static final int MODE_CLOCK = 2;
+
private final TimePickerDelegate mDelegate;
/**
@@ -77,15 +80,19 @@
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
- final boolean legacyMode = a.getBoolean(R.styleable.TimePicker_legacyMode, true);
+ int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
a.recycle();
- if (legacyMode) {
- mDelegate = new LegacyTimePickerDelegate(
- this, context, attrs, defStyleAttr, defStyleRes);
- } else {
- mDelegate = new android.widget.TimePickerDelegate(
- this, context, attrs, defStyleAttr, defStyleRes);
+ switch (mode) {
+ case MODE_CLOCK:
+ mDelegate = new TimePickerSpinnerDelegate(
+ this, context, attrs, defStyleAttr, defStyleRes);
+ break;
+ case MODE_SPINNER:
+ default:
+ mDelegate = new TimePickerClockDelegate(
+ this, context, attrs, defStyleAttr, defStyleRes);
+ break;
}
}
diff --git a/core/java/android/widget/LegacyTimePickerDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
similarity index 98%
rename from core/java/android/widget/LegacyTimePickerDelegate.java
rename to core/java/android/widget/TimePickerClockDelegate.java
index 70db211..59ec6d3 100644
--- a/core/java/android/widget/LegacyTimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -44,7 +44,7 @@
/**
* A delegate implementing the basic TimePicker
*/
-class LegacyTimePickerDelegate extends TimePicker.AbstractTimePickerDelegate {
+class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private static final boolean DEFAULT_ENABLED_STATE = true;
@@ -100,8 +100,8 @@
}
};
- public LegacyTimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
+ public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
super(delegator, context);
// process style attributes
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
similarity index 99%
rename from core/java/android/widget/TimePickerDelegate.java
rename to core/java/android/widget/TimePickerSpinnerDelegate.java
index c68619c..4e9a39f 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -51,7 +51,7 @@
/**
* A view for selecting the time of day, in either 24 hour or AM/PM mode.
*/
-class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implements
+class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements
RadialTimePickerView.OnValueSelectedListener {
private static final String TAG = "TimePickerDelegate";
@@ -119,8 +119,8 @@
private Calendar mTempCalendar;
- public TimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
+ public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
super(delegator, context);
// process style attributes
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3a02ab9..c4c4362 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -363,11 +363,7 @@
if (argv[i][1] == '-' && argv[i][2] == 0) {
return i+1;
}
-
- JavaVMOption opt;
- memset(&opt, 0, sizeof(opt));
- opt.optionString = (char*)argv[i];
- mOptions.add(opt);
+ addOption(argv[i]);
}
return i;
}
@@ -401,6 +397,14 @@
//ALOGD("language=%s region=%s\n", language, region);
}
+void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
+{
+ JavaVMOption opt;
+ opt.optionString = optionString;
+ opt.extraInfo = extraInfo;
+ mOptions.add(opt);
+}
+
/*
* Parse a property containing space-separated options that should be
* passed directly to the VM, e.g. "-Xmx32m -verbose:gc -Xregenmap".
@@ -413,8 +417,6 @@
*/
void AndroidRuntime::parseExtraOpts(char* extraOptsBuf, const char* quotingArg)
{
- JavaVMOption opt;
- memset(&opt, 0, sizeof(opt));
char* start = extraOptsBuf;
char* end = NULL;
while (*start != '\0') {
@@ -429,13 +431,10 @@
if (*end == ' ')
*end++ = '\0'; /* mark end, advance to indicate more */
- opt.optionString = start;
if (quotingArg != NULL) {
- JavaVMOption quotingOpt;
- quotingOpt.optionString = quotingArg;
- mOptions.add(quotingOpt);
+ addOption(quotingArg);
}
- mOptions.add(opt);
+ addOption(start);
start = end;
}
}
@@ -463,13 +462,35 @@
if (buffer[runtimeArgLen] == '\0') {
return false;
}
+ addOption(buffer);
+ return true;
+}
- JavaVMOption opt;
- memset(&opt, 0, sizeof(opt));
-
- opt.optionString = buffer;
- mOptions.add(opt);
-
+/*
+ * Reads a "property" into "buffer". If the property is non-empty, it
+ * is treated as a dex2oat compiler option that should be
+ * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
+ *
+ * The "compilerArg" is a prefix for the option such as "--compiler-filter=".
+ *
+ * The "quotingArg" should be "-Ximage-compiler-option" or "-Xcompiler-option".
+ *
+ * If an option is found, it is added to mOptions and true is
+ * returned. Otherwise false is returned.
+ */
+bool AndroidRuntime::parseCompilerOption(const char* property,
+ char* buffer,
+ const char* compilerArg,
+ const char* quotingArg)
+{
+ strcpy(buffer, compilerArg);
+ size_t compilerArgLen = strlen(compilerArg);
+ property_get(property, buffer+compilerArgLen, "");
+ if (buffer[compilerArgLen] == '\0') {
+ return false;
+ }
+ addOption(quotingArg);
+ addOption(buffer);
return true;
}
@@ -497,22 +518,10 @@
if (buffer[runtimeArgLen] == '\0') {
return false;
}
-
- JavaVMOption opt;
- memset(&opt, 0, sizeof(opt));
-
- opt.optionString = quotingArg;
- mOptions.add(opt);
-
- opt.optionString = "--runtime-arg";
- mOptions.add(opt);
-
- opt.optionString = quotingArg;
- mOptions.add(opt);
-
- opt.optionString = buffer;
- mOptions.add(opt);
-
+ addOption(quotingArg);
+ addOption("--runtime-arg");
+ addOption(quotingArg);
+ addOption(buffer);
return true;
}
@@ -536,7 +545,6 @@
{
int result = -1;
JavaVMInitArgs initArgs;
- JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
@@ -556,9 +564,12 @@
char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
+ char voldDecryptBuf[PROPERTY_VALUE_MAX];
enum {
kEMDefault,
kEMIntPortable,
@@ -594,16 +605,13 @@
ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
/* extended JNI checking */
- opt.optionString = "-Xcheck:jni";
- mOptions.add(opt);
+ addOption("-Xcheck:jni");
/* set a cap on JNI global references */
- opt.optionString = "-Xjnigreflimit:2000";
- mOptions.add(opt);
+ addOption("-Xjnigreflimit:2000");
/* with -Xcheck:jni, this provides a JNI function call trace */
- //opt.optionString = "-verbose:jni";
- //mOptions.add(opt);
+ //addOption("-verbose:jni");
}
property_get("dalvik.vm.execution-mode", propBuf, "");
@@ -620,15 +628,13 @@
property_get("dalvik.vm.check-dex-sum", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
/* perform additional DEX checksum tests */
- opt.optionString = "-Xcheckdexsum";
- mOptions.add(opt);
+ addOption("-Xcheckdexsum");
}
property_get("log.redirect-stdio", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
/* convert stdout/stderr to log messages */
- opt.optionString = "-Xlog-stdio";
- mOptions.add(opt);
+ addOption("-Xlog-stdio");
}
strcpy(enableAssertBuf, "-ea:");
@@ -638,8 +644,7 @@
if (strcmp(enableAssertBuf+sizeof("-ea:")-1, "all") == 0)
enableAssertBuf[3] = '\0'; // truncate to "-ea"
ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
- opt.optionString = enableAssertBuf;
- mOptions.add(opt);
+ addOption(enableAssertBuf);
} else {
ALOGV("Assertions disabled\n");
}
@@ -650,27 +655,18 @@
}
/* route exit() to our handler */
- opt.extraInfo = (void*) runtime_exit;
- opt.optionString = "exit";
- mOptions.add(opt);
+ addOption("exit", (void*) runtime_exit);
/* route fprintf() to our handler */
- opt.extraInfo = (void*) runtime_vfprintf;
- opt.optionString = "vfprintf";
- mOptions.add(opt);
+ addOption("vfprintf", (void*) runtime_vfprintf);
/* register the framework-specific "is sensitive thread" hook */
- opt.extraInfo = (void*) runtime_isSensitiveThread;
- opt.optionString = "sensitiveThread";
- mOptions.add(opt);
-
- opt.extraInfo = NULL;
+ addOption("sensitiveThread", (void*) runtime_isSensitiveThread);
/* enable verbose; standard options are { jni, gc, class } */
- //options[curOpt++].optionString = "-verbose:jni";
- opt.optionString = "-verbose:gc";
- mOptions.add(opt);
- //options[curOpt++].optionString = "-verbose:class";
+ //addOption("-verbose:jni");
+ addOption("-verbose:gc");
+ //addOption("-verbose:class");
/*
* The default starting and maximum size of the heap. Larger
@@ -680,8 +676,7 @@
parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
// Increase the main thread's interpreter stack size for bug 6315322.
- opt.optionString = "-XX:mainThreadStackSize=24K";
- mOptions.add(opt);
+ addOption("-XX:mainThreadStackSize=24K");
// Set the max jit code cache size. Note: size of 0 will disable the JIT.
parseRuntimeOption("dalvik.vm.jit.codecachesize",
@@ -697,8 +692,7 @@
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
- opt.optionString = "-XX:LowMemoryMode";
- mOptions.add(opt);
+ addOption("-XX:LowMemoryMode");
}
parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
@@ -723,8 +717,7 @@
}
if (val != NULL) {
- opt.optionString = val;
- mOptions.add(opt);
+ addOption(val);
}
}
@@ -739,27 +732,22 @@
}
if (val != NULL) {
- opt.optionString = val;
- mOptions.add(opt);
+ addOption(val);
}
}
opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */
if (opc != NULL) {
- opt.optionString = "-Xgenregmap";
- mOptions.add(opt);
+ addOption("-Xgenregmap");
/* turn on precise GC while we're at it */
- opt.optionString = "-Xgc:precise";
- mOptions.add(opt);
+ addOption("-Xgc:precise");
}
}
/* enable debugging; set suspend=y to pause during VM init */
/* use android ADB transport */
- opt.optionString =
- "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
- mOptions.add(opt);
+ addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
parseRuntimeOption("dalvik.vm.lockprof.threshold",
lockProfThresholdBuf,
@@ -772,14 +760,11 @@
parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:");
if (executionMode == kEMIntPortable) {
- opt.optionString = "-Xint:portable";
- mOptions.add(opt);
+ addOption("-Xint:portable");
} else if (executionMode == kEMIntFast) {
- opt.optionString = "-Xint:fast";
- mOptions.add(opt);
+ addOption("-Xint:fast");
} else if (executionMode == kEMJitCompiler) {
- opt.optionString = "-Xint:jit";
- mOptions.add(opt);
+ addOption("-Xint:jit");
}
// libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
@@ -787,11 +772,27 @@
bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
if (libart) {
+ // If we booting without the real /data, don't spend time compiling.
+ property_get("vold.decrypt", voldDecryptBuf, "");
+ bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
+ (strcmp(voldDecryptBuf, "1") == 0));
+
// Extra options for boot.art/boot.oat image generation.
parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
"-Xms", "-Ximage-compiler-option");
parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
"-Xmx", "-Ximage-compiler-option");
+ if (skip_compilation) {
+ addOption("-Ximage-compiler-option");
+ addOption("--compiler-filter=verify-none");
+ } else {
+ parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
+ "--compiler-filter=", "-Ximage-compiler-option");
+ }
+ addOption("-Ximage-compiler-option");
+ addOption("--image-classes-zip=/system/framework/framework.jar");
+ addOption("-Ximage-compiler-option");
+ addOption("--image-classes=preloaded-classes");
property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
@@ -800,8 +801,16 @@
"-Xms", "-Xcompiler-option");
parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
"-Xmx", "-Xcompiler-option");
+ if (skip_compilation) {
+ addOption("-Xcompiler-option");
+ addOption("--compiler-filter=interpret-only");
+ } else {
+ parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
+ "--compiler-filter=", "-Xcompiler-option");
+ }
property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
+
}
/* extra options; parse this late so it overrides others */
@@ -813,11 +822,8 @@
strcpy(langOption, "-Duser.language=");
strcpy(regionOption, "-Duser.region=");
readLocale(langOption, regionOption);
- opt.extraInfo = NULL;
- opt.optionString = langOption;
- mOptions.add(opt);
- opt.optionString = regionOption;
- mOptions.add(opt);
+ addOption(langOption);
+ addOption(regionOption);
}
/*
@@ -827,16 +833,14 @@
// Whether or not the profiler should be enabled.
property_get("dalvik.vm.profiler", propBuf, "0");
if (propBuf[0] == '1') {
- opt.optionString = "-Xenable-profiler";
- mOptions.add(opt);
+ addOption("-Xenable-profiler");
}
// Whether the profile should start upon app startup or be delayed by some random offset
// (in seconds) that is bound between 0 and a fixed value.
property_get("dalvik.vm.profile.start-immed", propBuf, "0");
if (propBuf[0] == '1') {
- opt.optionString = "-Xprofile-start-immediately";
- mOptions.add(opt);
+ addOption("-Xprofile-start-immediately");
}
// Number of seconds during profile runs.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2baa599..771690e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4260,8 +4260,6 @@
<attr name="internalLayout" format="reference" />
<!-- @hide The layout of the legacy DatePicker. -->
<attr name="legacyLayout" />
- <!-- @hide Enables or disable the use of the legacy layout for the DatePicker. -->
- <attr name="legacyMode" />
<!-- The background color for the date selector 's day of week. -->
<attr name="dayOfWeekBackgroundColor" format="color" />
<!-- The text color for the date selector's day of week. -->
@@ -4288,6 +4286,15 @@
if the text color does not explicitly have a color set for the
selected state. -->
<attr name="calendarSelectedTextColor" format="color" />
+ <!-- Defines the look of the widget. Prior to the L release, the only choice was
+ spinner. As of L, with the Material theme selected, the default layout is calendar,
+ but this attribute can be used to force spinner to be used instead. -->
+ <attr name="datePickerMode">
+ <!-- Date picker with spinner controls to select the date. -->
+ <enum name="spinner" value="1" />
+ <!-- Date picker with calendar to select the date. -->
+ <enum name="calendar" value="2" />
+ </attr>
</declare-styleable>
<declare-styleable name="TwoLineListItem">
@@ -4557,8 +4564,6 @@
</declare-styleable>
<declare-styleable name="TimePicker">
- <!-- @hide Enables or disable the use of the legacy layout for the TimePicker. -->
- <attr name="legacyMode" format="boolean" />
<!-- @hide The layout of the legacy time picker. -->
<attr name="legacyLayout" format="reference" />
<!-- @hide The layout of the time picker. -->
@@ -4587,6 +4592,15 @@
<attr name="amPmSelectedBackgroundColor" format="color" />
<!-- The color for the hours/minutes selector of the TimePicker. -->
<attr name="numbersSelectorColor" format="color" />
+ <!-- Defines the look of the widget. Prior to the L release, the only choice was
+ spinner. As of L, with the Material theme selected, the default layout is clock,
+ but this attribute can be used to force spinner to be used instead. -->
+ <attr name="timePickerMode">
+ <!-- Time picker with spinner controls to select the time. -->
+ <enum name="spinner" value="1" />
+ <!-- Time picker with clock face to select the time. -->
+ <enum name="clock" value="2" />
+ </attr>
</declare-styleable>
<!-- ========================= -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 08398f0..73aaafd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2562,4 +2562,7 @@
<public type="raw" name="nodomain"/>
<public type="attr" name="contentRatingSystemXml"/>
+
+ <public type="attr" name="datePickerMode"/>
+ <public type="attr" name="timePickerMode"/>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4a70952..a5cac6b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -568,12 +568,12 @@
</style>
<style name="Widget.TimePicker">
- <item name="legacyMode">true</item>
+ <item name="timePickerMode">spinner</item>
<item name="legacyLayout">@layout/time_picker_legacy</item>
</style>
<style name="Widget.DatePicker">
- <item name="legacyMode">true</item>
+ <item name="datePickerMode">spinner</item>
<item name="legacyLayout">@layout/date_picker_legacy</item>
<item name="calendarViewShown">false</item>
</style>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index d79e46d..2a54ccf 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -462,7 +462,7 @@
</style>
<style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
- <item name="legacyMode">true</item>
+ <item name="timePickerMode">spinner</item>
<item name="legacyLayout">@layout/time_picker_legacy_holo</item>
<!-- Attributes for new-style TimePicker. -->
<item name="internalLayout">@layout/time_picker_holo</item>
@@ -479,7 +479,7 @@
</style>
<style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
- <item name="legacyMode">true</item>
+ <item name="datePickerMode">spinner</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<item name="internalLayout">@layout/date_picker_holo</item>
<item name="calendarViewShown">true</item>
@@ -886,7 +886,7 @@
<style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker" />
<style name="Widget.Holo.Light.TimePicker" parent="Widget.TimePicker">
- <item name="legacyMode">true</item>
+ <item name="timePickerMode">spinner</item>
<item name="legacyLayout">@layout/time_picker_legacy_holo</item>
<!-- Non-legacy styling -->
<item name="internalLayout">@layout/time_picker_holo</item>
@@ -903,7 +903,7 @@
</style>
<style name="Widget.Holo.Light.DatePicker" parent="Widget.DatePicker">
- <item name="legacyMode">true</item>
+ <item name="datePickerMode">spinner</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<item name="internalLayout">@layout/date_picker_holo</item>
<item name="calendarViewShown">true</item>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
index a899c4d..256ef00 100644
--- a/core/res/res/values/styles_leanback.xml
+++ b/core/res/res/values/styles_leanback.xml
@@ -23,12 +23,12 @@
</style>
<style name="Widget.Leanback.TimePicker" parent="Widget.Material.TimePicker">
- <item name="legacyMode">true</item>
+ <item name="timePickerMode">spinner</item>
<item name="legacyLayout">@layout/time_picker_legacy_leanback</item>
</style>
<style name="Widget.Leanback.DatePicker" parent="Widget.Material.DatePicker">
- <item name="legacyMode">true</item>
+ <item name="datePickerMode">spinner</item>
</style>
<style name="Widget.Leanback.NumberPicker" parent="Widget.Material.NumberPicker">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2dc0438..97d4bf6 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -587,7 +587,7 @@
</style>
<style name="Widget.Material.TimePicker" parent="Widget.TimePicker">
- <item name="legacyMode">false</item>
+ <item name="timePickerMode">clock</item>
<item name="legacyLayout">@layout/time_picker_legacy_holo</item>
<!-- Attributes for new-style TimePicker. -->
<item name="internalLayout">@layout/time_picker_holo</item>
@@ -604,7 +604,7 @@
</style>
<style name="Widget.Material.DatePicker" parent="Widget.DatePicker">
- <item name="legacyMode">false</item>
+ <item name="datePickerMode">calendar</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<!-- Attributes for new-style DatePicker. -->
<item name="internalLayout">@layout/date_picker_holo</item>
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 45aa745..51e47e6 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -116,10 +116,15 @@
private:
static int startReg(JNIEnv* env);
+ void addOption(const char* optionString, void* extra_info = NULL);
bool parseRuntimeOption(const char* property,
char* buffer,
const char* runtimeArg,
const char* defaultArg = "");
+ bool parseCompilerOption(const char* property,
+ char* buffer,
+ const char* compilerArg,
+ const char* quotingArg);
bool parseCompilerRuntimeOption(const char* property,
char* buffer,
const char* runtimeArg,
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index d5719c8..20b8e7c 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -82,4 +82,5 @@
List<TvStreamConfig> getAvailableTvStreamConfigList(in String inputId, int userId);
boolean captureFrame(in String inputId, in Surface surface, in TvStreamConfig config,
int userId);
+ boolean isSingleSessionActive(int userId);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d556369..6e075b2 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -948,6 +948,20 @@
}
/**
+ * Returns true if there is only a single TV input session.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isSingleSessionActive() {
+ try {
+ return mService.isSingleSessionActive(mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* The Session provides the per-session functionality of TV inputs.
* @hide
*/
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 9dd6bc2..1835b8e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -57,7 +57,7 @@
}
public KeyguardSecurityContainer(Context context) {
- this(null, null, 0);
+ this(context, null, 0);
}
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
@@ -240,10 +240,13 @@
boolean showTimeout = false;
if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
- // If we reach this code, it means the user has installed a DevicePolicyManager
- // that requests device wipe after N attempts. Once we get below the grace
- // period, we'll post this dialog every time as a clear warning until the
- // bombshell hits and the device is wiped.
+ // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
+ // N attempts. Once we get below the grace period, we post this dialog every time as a
+ // clear warning until the deletion fires.
+ //
+ // TODO: Show a different dialog depending on whether the device will be completely
+ // wiped (i.e. policy is set for the primary profile of the USER_OWNER) or a single
+ // secondary user or managed profile will be removed.
if (remainingBeforeWipe > 0) {
showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
} else {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 58cbaba..0d79ee2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -229,13 +229,16 @@
private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
@Override
- public void onTrustChanged(boolean enabled, int userId) {
+ public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
mUserHasTrust.put(userId, enabled);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onTrustChanged(userId);
+ if (enabled && initiatedByUser) {
+ cb.onTrustInitiatedByUser(userId);
+ }
}
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 4827e79..0acb9d0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -179,6 +179,11 @@
public void onTrustManagedChanged(int userId) { }
/**
+ * Called when the user has proved to a trust agent that they want to use the device.
+ */
+ public void onTrustInitiatedByUser(int userId) { }
+
+ /**
* Called when a fingerprint is recognized.
* @param userId
*/
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
index 8ddb9be..57f7e65 100644
--- a/packages/SystemUI/res/color/qs_user_detail_name.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_name.xml
@@ -17,6 +17,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_activated="true" android:color="#ffffffff" />
+ <item android:state_activated="true" android:color="@color/current_user_border_color" />
<item android:color="#66ffffff" /> <!-- 40% white -->
</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
index 0d5cd2e..d10a96d 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
+++ b/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
@@ -16,7 +16,19 @@
~ limitations under the License
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_activated="true" android:drawable="@drawable/ic_account_circle" />
- <item android:drawable="@drawable/ic_account_circle_qs_muted" />
-</selector>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <group
+ android:scaleX="1.2"
+ android:scaleY="1.2"
+ android:pivotX="12.0"
+ android:pivotY="12.0">
+ <path
+ android:fillColor="@color/qs_user_detail_icon_muted"
+ android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
deleted file mode 100644
index 7b8b89f..0000000
--- a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <group
- android:scaleX="1.2"
- android:scaleY="1.2"
- android:pivotX="12.0"
- android:pivotY="12.0">
- <path
- android:fillColor="@color/qs_user_detail_icon_muted"
- android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
new file mode 100644
index 0000000..f296076
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <group
+ android:scaleX="1.2"
+ android:scaleY="1.2"
+ android:pivotX="12.0"
+ android:pivotY="12.0">
+ <path
+ android:fillColor="@color/qs_user_detail_icon_muted"
+ android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 0e2b6d6..650ee5d 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -14,6 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- extends FrameLayout -->
<com.android.systemui.statusbar.policy.HeadsUpNotificationView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
@@ -21,11 +22,12 @@
android:background="@drawable/heads_up_scrim">
<FrameLayout
+ android:layout_width="@dimen/notification_panel_width"
android:layout_height="wrap_content"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
android:paddingStart="@dimen/notification_side_padding"
android:paddingEnd="@dimen/notification_side_padding"
android:elevation="8dp"
- android:id="@+id/content_holder"
- style="@style/NotificationsQuickSettings" />
+ android:id="@+id/content_holder" />
</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
index d17390e..2e67376 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -16,7 +16,9 @@
~ limitations under the License
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- LinearLayout -->
+<com.android.systemui.qs.tiles.UserDetailItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -24,17 +26,21 @@
android:layout_marginEnd="8dp"
android:gravity="center_vertical"
android:clickable="true"
- android:background="@drawable/ripple_drawable">
- <TextView android:id="@+id/name"
+ android:background="@drawable/ripple_drawable"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ sysui:activatedFontFamily="sans-serif-medium">
+ <TextView android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.UserName"
/>
- <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/picture"
+ <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture"
android:layout_width="@dimen/max_avatar_size"
android:layout_height="@dimen/max_avatar_size"
android:contentDescription="@null"
sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
+ sysui:framePadding="6dp"
sysui:activeFrameColor="@color/current_user_border_color" />
-</LinearLayout>
\ No newline at end of file
+</com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 403860c..5ceed84 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -25,7 +25,10 @@
android:orientation="vertical"
android:gravity="top|center_horizontal"
android:paddingTop="16dp"
- android:paddingBottom="20dp">
+ android:paddingBottom="20dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ systemui:activatedFontFamily="sans-serif-medium">
<com.android.systemui.statusbar.phone.UserAvatarView
android:id="@+id/user_picture"
@@ -33,6 +36,7 @@
android:layout_height="@dimen/max_avatar_size"
android:layout_marginBottom="12dp"
systemui:frameWidth="2dp"
+ systemui:framePadding="6dp"
systemui:activeFrameColor="@color/current_user_border_color"/>
<TextView
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index fa1077b..4eab9c7 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -50,20 +50,19 @@
android:visibility="gone"
/>
- <include
- layout="@layout/keyguard_status_bar"
- android:visibility="invisible" />
-
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
- style="@style/NotificationsQuickSettings"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
android:id="@+id/notification_container_parent"
android:clipToPadding="false"
android:clipChildren="false">
<com.android.systemui.statusbar.phone.ObservableScrollView
android:id="@+id/scroll_view"
- android:layout_width="match_parent"
+ android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
android:scrollbars="none"
android:overScrollMode="never"
android:fillViewport="true">
@@ -95,8 +94,9 @@
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
- android:layout_width="match_parent"
+ android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
android:layout_marginBottom="@dimen/close_handle_underlap"/>
<ViewStub
@@ -107,6 +107,10 @@
android:layout_gravity="end"
android:layout="@layout/keyguard_user_switcher" />
+ <include
+ layout="@layout/keyguard_status_bar"
+ android:visibility="invisible" />
+
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
<include layout="@layout/status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 1afde69..688a88c 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -20,8 +20,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/header"
- style="@style/StatusBarHeader"
+ android:layout_width="@dimen/notification_panel_width"
android:layout_height="@dimen/status_bar_header_height"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
android:paddingStart="@dimen/notification_side_padding"
android:paddingEnd="@dimen/notification_side_padding"
android:baselineAligned="false"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 112f3a9..3765fe8 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -15,8 +15,10 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/volume_panel_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/notification_side_padding"
+ android:layout_marginRight="@dimen/notification_side_padding"
android:background="@drawable/qs_background_primary"
android:translationZ="@dimen/volume_panel_z"
android:layout_marginBottom="@dimen/volume_panel_z">
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 5755029..2b1a4dc 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -24,9 +24,6 @@
value at runtime for some things) -->
<integer name="status_bar_recents_bg_gradient_degrees">90</integer>
- <!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">4</integer>
-
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">2</integer>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 42c4392..9b772bd 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -41,6 +41,7 @@
<!-- The side padding for the task stack as a percentage of the width. -->
<item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.2229</item>
- <!-- Width of the zen mode interstitial dialog. -->
- <dimen name="zen_mode_dialog_width">384dp</dimen>
+ <!-- Standard notification width + gravity -->
+ <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
+ <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 9f4c364..4f6d209 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -20,9 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">4</integer>
-
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">4</integer>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 6beccc5..7cdc078 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -16,12 +16,9 @@
*/
-->
<resources>
- <!-- The width of the notification panel window: 400 + 16 + 16 (padding in the bg drawable) -->
- <dimen name="notification_panel_width">432dp</dimen>
-
- <!-- Gravity for the notification panel -->
- <!-- 0x31 = top|center_horizontal -->
- <integer name="notification_panel_layout_gravity">0x31</integer>
+ <!-- Standard notification width + gravity -->
+ <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
+ <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
<!-- Diameter of outer shape drawable shown in navbar search-->
<dimen name="navbar_search_outerring_diameter">430dip</dimen>
@@ -49,9 +46,6 @@
<!-- The side padding for the task stack as a percentage of the width. -->
<item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item>
- <!-- Width of the zen mode interstitial dialog. -->
- <dimen name="zen_mode_dialog_width">384dp</dimen>
-
<!-- The fraction of the screen height where the clock on the Keyguard has its center. The
max value is used when no notifications are displaying, and the min value is when the
highest possible number of notifications are showing. -->
@@ -78,9 +72,6 @@
<!-- Margin on the left side of the carrier text on Keyguard -->
<dimen name="keyguard_carrier_text_margin">24dp</dimen>
- <!-- end margin for system icons if multi user switch is hidden -->
- <dimen name="system_icons_switcher_hidden_expanded_margin">20dp</dimen>
-
<!-- The width/height of the phone/camera/unlock icon on keyguard. -->
<dimen name="keyguard_affordance_height">80dp</dimen>
<dimen name="keyguard_affordance_width">120dp</dimen>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 88372bc..5daf08e 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -19,17 +19,6 @@
<item name="android:layout_width">480dp</item>
</style>
- <style name="NotificationsQuickSettings">
- <item name="android:layout_width">@dimen/notification_panel_width</item>
- <item name="android:layout_height">match_parent</item>
- <item name="android:layout_gravity">top|center_horizontal</item>
- </style>
-
- <style name="StatusBarHeader">
- <item name="android:layout_width">@dimen/notification_panel_width</item>
- <item name="android:layout_gravity">center_horizontal</item>
- </style>
-
<style name="SearchPanelCard">
<item name="android:layout_width">550dp</item>
<item name="android:layout_height">@dimen/search_panel_card_height</item>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 7695b12..3cd5f67 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -22,12 +22,8 @@
be situations where they don't sync up perfectly with PhoneStatusBar. -->
<!-- ======================================== -->
- <!-- The width of the ticker, including the icon -->
- <dimen name="notification_ticker_width">360dp</dimen>
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">1dp</dimen>
- <!-- The width of the notification panel window -->
- <dimen name="notification_panel_width">512dp</dimen>
<!-- The minimum height of the notification panel window -->
<dimen name="notification_panel_min_height">770dp</dimen>
<!-- Bottom margin (from display edge) for status bar panels -->
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index d8d170d..8bd3c39 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -56,9 +56,14 @@
</attr>
<declare-styleable name="UserAvatarView">
<attr name="frameWidth" format="dimension" />
+ <attr name="framePadding" format="dimension" />
<attr name="activeFrameColor" format="color" />
<attr name="frameColor" />
</declare-styleable>
+ <declare-styleable name="UserDetailItemView">
+ <attr name="regularFontFamily" format="string" />
+ <attr name="activatedFontFamily" format="string" />
+ </declare-styleable>
<declare-styleable name="DateView">
<attr name="datePattern" format="string" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1cdcc2b..c3ea8f8 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -103,4 +103,6 @@
<color name="notification_guts_btn_color">#FFFFFFFF</color>
<color name="search_panel_card_color">#ffffff</color>
+
+ <color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index efddc62..11a8063 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -136,9 +136,14 @@
<!-- Height of the status bar header bar when on Keyguard -->
<dimen name="status_bar_header_height_keyguard">40dp</dimen>
+ <!-- Width for the notification panel and related windows -->
+ <dimen name="match_parent">-1px</dimen>
+ <dimen name="standard_notification_panel_width">416dp</dimen><!-- includes notification_side_padding on each side -->
+ <dimen name="notification_panel_width">@dimen/match_parent</dimen>
+
<!-- Gravity for the notification panel -->
- <!-- 0x37 = fill_horizontal|top -->
- <integer name="notification_panel_layout_gravity">0x37</integer>
+ <integer name="standard_notification_panel_layout_gravity">0x31</integer><!-- top|center_horizontal -->
+ <integer name="notification_panel_layout_gravity">0x37</integer><!-- fill_horizontal|top -->
<!-- Height of the carrier/wifi name label -->
<dimen name="carrier_label_height">24dp</dimen>
@@ -269,9 +274,6 @@
<!-- The height of the speed bump view. -->
<dimen name="speed_bump_height">16dp</dimen>
- <!-- Width of the zen mode interstitial dialog. -->
- <dimen name="zen_mode_dialog_width">320dp</dimen>
-
<!-- Lockscreen affordance drag distance for camera and phone. -->
<dimen name="affordance_drag_distance">100dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 83a9a81..601a77b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -672,6 +672,13 @@
<string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
<!-- Related to user switcher --><skip/>
+
+ <!-- Label for the adding a new user in the user switcher [CHAR LIMIT=35] -->
+ <string name="user_add_user">Add user</string>
+
+ <!-- Name for a freshly added user [CHAR LIMIT=30] -->
+ <string name="user_new_user_name">New user</string>
+
<!-- Name for the guest user [CHAR LIMIT=35] -->
<string name="guest_nickname">Guest</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 197c0f1..5db6912 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -103,7 +103,7 @@
<style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
<item name="android:textSize">16sp</item>
<item name="android:textStyle">normal</item>
- <item name="android:textColor">#ffffff</item>
+ <item name="android:textColor">@color/qs_user_detail_name</item>
</style>
<style name="TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" />
@@ -254,16 +254,7 @@
<item name="android:colorControlActivated">@color/system_accent_color</item>
</style>
- <style name="NotificationsQuickSettings">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">match_parent</item>
- </style>
-
- <style name="StatusBarHeader">
- <item name="android:layout_width">match_parent</item>
- </style>
-
- <style name="QSBorderlessButton">
+ <style name="QSBorderlessButton">
<item name="android:padding">12dp</item>
<item name="android:background">@drawable/btn_borderless_rect</item>
<item name="android:gravity">center</item>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index d765aab..759d540 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -16,11 +16,14 @@
package com.android.systemui.qs.tiles;
+import com.android.internal.util.ArrayUtils;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.UserAvatarView;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -36,6 +39,8 @@
private UserAvatarView mAvatar;
private TextView mName;
+ private Typeface mRegularTypeface;
+ private Typeface mActivatedTypeface;
public UserDetailItemView(Context context) {
this(context, null);
@@ -52,6 +57,21 @@
public UserDetailItemView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.UserDetailItemView, defStyleAttr, defStyleRes);
+ final int N = a.getIndexCount();
+ for (int i = 0; i < N; i++) {
+ int attr = a.getIndex(i);
+ switch (attr) {
+ case R.styleable.UserDetailItemView_regularFontFamily:
+ mRegularTypeface = Typeface.create(a.getString(attr), 0 /* style */);
+ break;
+ case R.styleable.UserDetailItemView_activatedFontFamily:
+ mActivatedTypeface = Typeface.create(a.getString(attr), 0 /* style */);
+ break;
+ }
+ }
+ a.recycle();
}
public static UserDetailItemView convertOrInflate(Context context, View convertView,
@@ -77,6 +97,23 @@
protected void onFinishInflate() {
mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
mName = (TextView) findViewById(R.id.user_name);
+ if (mRegularTypeface == null) {
+ mRegularTypeface = mName.getTypeface();
+ }
+ if (mActivatedTypeface == null) {
+ mActivatedTypeface = mName.getTypeface();
+ }
+ updateTypeface();
}
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ updateTypeface();
+ }
+
+ private void updateTypeface() {
+ boolean activated = ArrayUtils.contains(getDrawableState(), android.R.attr.state_activated);
+ mName.setTypeface(activated ? mActivatedTypeface : mRegularTypeface);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 67eef56..8cff81a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -83,7 +83,7 @@
mContext, convertView, parent);
String name = getName(mContext, item);
if (item.picture == null) {
- v.bind(name, mContext.getDrawable(R.drawable.ic_account_circle_qs));
+ v.bind(name, getDrawable(mContext, item));
} else {
v.bind(name, item.picture);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index c559253..d4c8ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -429,6 +429,9 @@
try {
panelWidth = r.getDimensionPixelSize(R.dimen.notification_panel_width);
} catch (Resources.NotFoundException e) {
+ }
+ if (panelWidth <= 0) {
+ // includes notification_panel_width==match_parent (-1)
panelWidth = mDisplayMetrics.widthPixels;
}
mPreviewWidth = panelWidth;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7ec0cc5..16e51c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -98,7 +98,7 @@
RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,
NotificationData.Environment {
public static final String TAG = "StatusBar";
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean MULTIUSER_DEBUG = false;
protected static final int MSG_SHOW_RECENT_APPS = 1019;
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 a3b7c92..e6b3818 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -32,6 +32,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -43,6 +44,7 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.MirrorView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -61,6 +63,7 @@
private KeyguardAffordanceHelper mAfforanceHelper;
private StatusBarHeaderView mHeader;
+ private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
private View mQsContainer;
private QSPanel mQsPanel;
@@ -70,7 +73,7 @@
private View mReserveNotificationSpace;
private MirrorView mSystemIconsCopy;
private View mQsNavbarScrim;
-
+ private View mNotificationContainerParent;
private NotificationStackScrollLayout mNotificationStackScroller;
private int mNotificationTopPadding;
private boolean mAnimateNextTopPaddingChange;
@@ -125,7 +128,6 @@
private Interpolator mFastOutSlowInInterpolator;
private Interpolator mFastOutLinearInterpolator;
- private Interpolator mLinearOutSlowInInterpolator;
private ObjectAnimator mClockAnimator;
private int mClockAnimationTarget = -1;
private int mTopPaddingAdjustment;
@@ -180,6 +182,7 @@
mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
mScrollView.setListener(this);
mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
+ mNotificationContainerParent = findViewById(R.id.notification_container_parent);
mNotificationStackScroller = (NotificationStackScrollLayout)
findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
@@ -189,8 +192,6 @@
android.R.interpolator.fast_out_slow_in);
mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_linear_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.linear_out_slow_in);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -215,6 +216,32 @@
getResources().getDimensionPixelSize(R.dimen.notification_scrim_wait_distance);
}
+ public void updateResources() {
+ int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
+ int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
+ if (lp.width != panelWidth) {
+ lp.width = panelWidth;
+ lp.gravity = panelGravity;
+ mHeader.setLayoutParams(lp);
+ mHeader.post(mUpdateHeader);
+ }
+
+ lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
+ if (lp.width != panelWidth) {
+ lp.width = panelWidth;
+ lp.gravity = panelGravity;
+ mNotificationStackScroller.setLayoutParams(lp);
+ }
+
+ lp = (FrameLayout.LayoutParams) mScrollView.getLayoutParams();
+ if (lp.width != panelWidth) {
+ lp.width = panelWidth;
+ lp.gravity = panelGravity;
+ mScrollView.setLayoutParams(lp);
+ }
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -921,6 +948,9 @@
&& !mStackScrollerOverscrolling && mQsScrimEnabled
? View.VISIBLE
: View.INVISIBLE);
+ if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
+ mKeyguardUserSwitcher.hide();
+ }
}
private void setQsExpansion(float height) {
@@ -1685,4 +1715,15 @@
updateQsState();
}
}
+
+ public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
+ mKeyguardUserSwitcher = keyguardUserSwitcher;
+ }
+
+ private final Runnable mUpdateHeader = new Runnable() {
+ @Override
+ public void run() {
+ mHeader.updateEverything();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 7c6e47c..57b7401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -35,6 +35,7 @@
private View mScrollView;
private View mUserSwitcher;
private View mStackScroller;
+ private View mKeyguardStatusBar;
private boolean mInflated;
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
@@ -46,6 +47,7 @@
super.onFinishInflate();
mScrollView = findViewById(R.id.scroll_view);
mStackScroller = findViewById(R.id.notification_stack_scroller);
+ mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
userSwitcher.setOnInflateListener(this);
mUserSwitcher = userSwitcher;
@@ -61,18 +63,30 @@
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
+ boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
if (child == mScrollView) {
return super.drawChild(canvas, mStackScroller, drawingTime);
} else if (child == mStackScroller) {
- return super.drawChild(canvas, userSwitcherVisible ? mUserSwitcher : mScrollView,
+ return super.drawChild(canvas,
+ userSwitcherVisible && statusBarVisible ? mUserSwitcher
+ : statusBarVisible ? mKeyguardStatusBar
+ : userSwitcherVisible ? mUserSwitcher
+ : mScrollView,
drawingTime);
} else if (child == mUserSwitcher) {
- return super.drawChild(canvas, userSwitcherVisible ? mScrollView : mUserSwitcher,
+ return super.drawChild(canvas,
+ userSwitcherVisible && statusBarVisible ? mKeyguardStatusBar
+ : mScrollView,
drawingTime);
- } else {
+ } else if (child == mKeyguardStatusBar) {
+ return super.drawChild(canvas,
+ userSwitcherVisible && statusBarVisible ? mScrollView
+ : mScrollView,
+ drawingTime);
+ }else {
return super.drawChild(canvas, child, drawingTime);
}
}
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 750fb39..1d678af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -799,13 +799,13 @@
mFlashlightController = new FlashlightController(mContext);
mKeyguardBottomArea.setFlashlightController(mFlashlightController);
- mUserSwitcherController = new UserSwitcherController(mContext);
mNextAlarmController = new NextAlarmController(mContext);
mKeyguardMonitor = new KeyguardMonitor();
+ mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor);
mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
(ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
- mKeyguardStatusBar, mUserSwitcherController);
+ mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
// Set up the quick settings tile panel
@@ -3030,11 +3030,20 @@
*/
void updateResources() {
// Update the quick setting tiles
- if (mQSPanel != null) mQSPanel.updateResources();
+ if (mQSPanel != null) {
+ mQSPanel.updateResources();
+ }
loadDimens();
mLinearOutSlowIn = AnimationUtils.loadInterpolator(
mContext, android.R.interpolator.linear_out_slow_in);
+
+ if (mNotificationPanel != null) {
+ mNotificationPanel.updateResources();
+ }
+ if (mHeadsUpNotificationView != null) {
+ mHeadsUpNotificationView.updateResources();
+ }
}
protected void loadDimens() {
@@ -3076,7 +3085,7 @@
mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
- if (false) Log.v(TAG, "updateResources");
+ if (DEBUG) Log.v(TAG, "updateResources");
}
// Visibility reporting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index b3051b4..0c62fd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -243,21 +243,25 @@
boolean changed = expanded != mExpanded;
mExpanded = expanded;
if (changed) {
- updateHeights();
- updateVisibilities();
- updateSystemIconsLayoutParams();
- updateClickTargets();
- updateMultiUserSwitch();
- if (mQSPanel != null) {
- mQSPanel.setExpanded(expanded);
- }
- updateClockScale();
- updateAvatarScale();
- updateClockLp();
- requestCaptureValues();
+ updateEverything();
}
}
+ public void updateEverything() {
+ updateHeights();
+ updateVisibilities();
+ updateSystemIconsLayoutParams();
+ updateClickTargets();
+ updateMultiUserSwitch();
+ if (mQSPanel != null) {
+ mQSPanel.setExpanded(mExpanded);
+ }
+ updateClockScale();
+ updateAvatarScale();
+ updateClockLp();
+ requestCaptureValues();
+ }
+
private void updateHeights() {
int height = mExpanded ? mExpandedHeight : mCollapsedHeight;
ViewGroup.LayoutParams lp = getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index 93561aa..101a5f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -38,6 +38,7 @@
private int mActiveFrameColor;
private int mFrameColor;
private float mFrameWidth;
+ private float mFramePadding;
private Bitmap mBitmap;
private Drawable mDrawable;
@@ -60,6 +61,9 @@
case R.styleable.UserAvatarView_frameWidth:
setFrameWidth(a.getDimension(attr, 0));
break;
+ case R.styleable.UserAvatarView_framePadding:
+ setFramePadding(a.getDimension(attr, 0));
+ break;
case R.styleable.UserAvatarView_activeFrameColor:
setActiveFrameColor(a.getColor(attr, 0));
break;
@@ -115,6 +119,11 @@
invalidate();
}
+ public void setFramePadding(float framePadding) {
+ mFramePadding = framePadding;
+ invalidate();
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -131,11 +140,11 @@
dwidth = mBitmap.getWidth();
dheight = mBitmap.getHeight();
} else if (mDrawable != null) {
- dwidth = mDrawable.getIntrinsicWidth();
- dheight = mDrawable.getIntrinsicHeight();
- mDrawable.setBounds(0, 0, dwidth, dheight);
vwidth -= 2 * (mFrameWidth - 1);
vheight -= 2 * (mFrameWidth - 1);
+ dwidth = vwidth;
+ dheight = vheight;
+ mDrawable.setBounds(0, 0, dwidth, dheight);
} else {
return;
}
@@ -183,7 +192,8 @@
if (frameColor != 0) {
mFramePaint.setColor(frameColor);
mFramePaint.setStrokeWidth(mFrameWidth);
- canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint);
+ canvas.drawCircle(halfW, halfH, halfSW + (mFramePadding - mFrameWidth) / 2f,
+ mFramePaint);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 2aceb95..6ae076f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -70,6 +70,15 @@
if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
}
+ public void updateResources() {
+ if (mContentHolder != null) {
+ final LayoutParams lp = (LayoutParams) mContentHolder.getLayoutParams();
+ lp.width = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
+ lp.gravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
+ mContentHolder.setLayoutParams(lp);
+ }
+ }
+
public void setBar(PhoneStatusBar bar) {
mBar = bar;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index a0312bc..203196e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.database.DataSetObserver;
-import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -26,7 +25,10 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.qs.tiles.UserDetailItemView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
import com.android.systemui.statusbar.phone.UserAvatarView;
/**
@@ -43,11 +45,14 @@
private final boolean mSimpleUserSwitcher;
public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
- KeyguardStatusBarView statusBarView, UserSwitcherController userSwitcherController) {
+ KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
+ UserSwitcherController userSwitcherController) {
if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
mUserSwitcher = (ViewGroup) userSwitcher.inflate();
+ mUserSwitcher.setBackground(new KeyguardUserSwitcherScrim(mUserSwitcher));
mStatusBarView = statusBarView;
mStatusBarView.setKeyguardUserSwitcher(this);
+ panelView.setKeyguardUserSwitcher(this);
mAdapter = new Adapter(context, userSwitcherController);
mAdapter.registerDataSetObserver(mDataSetObserver);
mSimpleUserSwitcher = userSwitcherController.isSimpleUserSwitcher();
@@ -74,7 +79,7 @@
* @see android.os.UserManager#isUserSwitcherEnabled()
*/
private boolean shouldExpandByDefault() {
- return mSimpleUserSwitcher || mAdapter.getSwitchableUsers() > 1;
+ return mSimpleUserSwitcher;
}
public void show() {
@@ -86,7 +91,7 @@
}
public void hide() {
- if (mUserSwitcher != null) {
+ if (mUserSwitcher != null && mUserSwitcher.getVisibility() == View.VISIBLE) {
// TODO: animate
mUserSwitcher.setVisibility(View.GONE);
mStatusBarView.setKeyguardUserSwitcherShowing(false);
@@ -140,21 +145,19 @@
public View getView(int position, View convertView, ViewGroup parent) {
UserSwitcherController.UserRecord item = getItem(position);
- if (convertView == null
+ if (!(convertView instanceof UserDetailItemView)
|| !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.keyguard_user_switcher_item, parent, false);
convertView.setOnClickListener(this);
}
+ UserDetailItemView v = (UserDetailItemView) convertView;
- TextView nameView = (TextView) convertView.findViewById(R.id.name);
- UserAvatarView pictureView = (UserAvatarView) convertView.findViewById(R.id.picture);
-
- nameView.setText(getName(mContext, item));
+ String name = getName(mContext, item);
if (item.picture == null) {
- pictureView.setDrawable(mContext.getDrawable(R.drawable.ic_account_circle_qs));
+ v.bind(name, getDrawable(mContext, item));
} else {
- pictureView.setBitmap(item.picture);
+ v.bind(name, item.picture);
}
convertView.setActivated(item.isCurrent);
convertView.setTag(item);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
new file mode 100644
index 0000000..3356afd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.LayoutDirection;
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * Gradient background for the user switcher on Keyguard.
+ */
+public class KeyguardUserSwitcherScrim extends Drawable
+ implements View.OnLayoutChangeListener {
+
+ private static final float OUTER_EXTENT = 2.5f;
+ private static final float INNER_EXTENT = 0.75f;
+
+ private int mDarkColor;
+ private int mTop;
+ private Paint mRadialGradientPaint = new Paint();
+
+ public KeyguardUserSwitcherScrim(View host) {
+ host.addOnLayoutChangeListener(this);
+ mDarkColor = host.getResources().getColor(
+ R.color.keyguard_user_switcher_background_gradient_color);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+ Rect bounds = getBounds();
+ float width = bounds.width() * OUTER_EXTENT;
+ float height = (mTop + bounds.height()) * OUTER_EXTENT;
+ canvas.translate(0, -mTop);
+ canvas.scale(1, height/width);
+ canvas.drawRect(isLtr ? bounds.right - width : 0, 0,
+ isLtr ? bounds.right : bounds.left + width, width, mRadialGradientPaint);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
+ int width = right - left;
+ float radius = width * OUTER_EXTENT;
+ boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+ mRadialGradientPaint.setShader(
+ new RadialGradient(isLtr ? width : 0, 0, radius,
+ new int[] { mDarkColor, Color.TRANSPARENT},
+ new float[] { Math.max(0f, width * INNER_EXTENT / radius), 1f},
+ Shader.TileMode.CLAMP));
+ mTop = top;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6e3656d..c48f3f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -34,6 +34,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
@@ -68,15 +69,18 @@
private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
= new GuestResumeSessionReceiver();
- private boolean mSimpleUserSwitcher;
+ private final KeyguardMonitor mKeyguardMonitor;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
private Dialog mExitGuestDialog;
private int mLastNonGuestUser = UserHandle.USER_OWNER;
+ private boolean mSimpleUserSwitcher;
+ private boolean mAddUsersWhenLocked;
- public UserSwitcherController(Context context) {
+ public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor) {
mContext = context;
mGuestResumeSessionReceiver.register(context);
+ mKeyguardMonitor = keyguardMonitor;
mUserManager = UserManager.get(context);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
@@ -87,11 +91,17 @@
mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
null /* permission */, null /* scheduler */);
- mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(),
- SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
- mSimpleUserSwitcherObserver);
+ mSettingsObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
+ mSettingsObserver);
+ // Fetch initial values.
+ mSettingsObserver.onChange(false);
+
+ keyguardMonitor.addCallback(mCallback);
refreshUsers(UserHandle.USER_NULL);
}
@@ -116,6 +126,7 @@
bitmaps.put(r.info.id, r.picture);
}
+ final boolean addUsersWhenLocked = mAddUsersWhenLocked;
new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
@SuppressWarnings("unchecked")
@Override
@@ -135,7 +146,8 @@
boolean isCurrent = currentId == info.id;
if (info.isGuest()) {
guestRecord = new UserRecord(info, null /* picture */,
- true /* isGuest */, isCurrent);
+ true /* isGuest */, isCurrent, false /* isAddUser */,
+ false /* isRestricted */);
} else if (info.supportsSwitchTo()) {
Bitmap picture = bitmaps.get(info.id);
if (picture == null) {
@@ -145,19 +157,40 @@
picture = BitmapHelper.createCircularClip(
picture, avatarSize, avatarSize);
}
- records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent));
+ records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent,
+ false /* isAddUser */, false /* isRestricted */));
}
}
+ boolean ownerCanCreateUsers = !mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_ADD_USER, UserHandle.OWNER);
+ boolean currentUserCanCreateUsers =
+ (currentId == UserHandle.USER_OWNER) && ownerCanCreateUsers;
+ boolean anyoneCanCreateUsers = ownerCanCreateUsers && addUsersWhenLocked;
+ boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+ && guestRecord == null;
+ boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+ && records.size() < UserManager.getMaxSupportedUsers();
+ boolean createIsRestricted = !addUsersWhenLocked;
+
if (!mSimpleUserSwitcher) {
if (guestRecord == null) {
- records.add(new UserRecord(null /* info */, null /* picture */,
- true /* isGuest */, false /* isCurrent */));
+ if (canCreateGuest) {
+ records.add(new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */,
+ false /* isAddUser */, createIsRestricted));
+ }
} else {
records.add(guestRecord);
}
}
+ if (canCreateUser) {
+ records.add(new UserRecord(null /* info */, null /* picture */,
+ false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
+ createIsRestricted));
+ }
+
return records;
}
@@ -168,7 +201,7 @@
notifyAdapters();
}
}
- }.execute((SparseArray)bitmaps);
+ }.execute((SparseArray) bitmaps);
}
private void notifyAdapters() {
@@ -190,8 +223,10 @@
int id;
if (record.isGuest && record.info == null) {
// No guest user. Create one.
- id = mUserManager.createGuest(mContext,
- mContext.getResources().getString(R.string.guest_nickname)).id;
+ id = mUserManager.createGuest(mContext, mContext.getString(R.string.guest_nickname)).id;
+ } else if (record.isAddUser) {
+ id = mUserManager.createUser(
+ mContext.getString(R.string.user_new_user_name), 0 /* flags */).id;
} else {
id = record.info.id;
}
@@ -260,6 +295,11 @@
if (shouldBeCurrent && !record.isGuest) {
mLastNonGuestUser = record.info.id;
}
+ if (currentId != UserHandle.USER_OWNER && record.isRestricted) {
+ // Immediately remove restricted records in case the AsyncTask is too slow.
+ mUsers.remove(i);
+ i--;
+ }
}
notifyAdapters();
}
@@ -272,10 +312,12 @@
}
};
- private final ContentObserver mSimpleUserSwitcherObserver = new ContentObserver(new Handler()) {
+ private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+ mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
refreshUsers(UserHandle.USER_NULL);
};
};
@@ -301,7 +343,22 @@
@Override
public int getCount() {
- return mController.mUsers.size();
+ boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
+ && mController.mKeyguardMonitor.isSecure();
+ if (!secureKeyguardShowing) {
+ return mController.mUsers.size();
+ }
+ // The lock screen is secure and showing. Filter out restricted records.
+ final int N = mController.mUsers.size();
+ int count = 0;
+ for (int i = 0; i < N; i++) {
+ if (mController.mUsers.get(i).isRestricted) {
+ break;
+ } else {
+ count++;
+ }
+ }
+ return count;
}
@Override
@@ -326,6 +383,8 @@
return context.getString(
item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
}
+ } else if (item.isAddUser) {
+ return context.getString(R.string.user_add_user);
} else {
return item.info.name;
}
@@ -342,6 +401,13 @@
}
return result;
}
+
+ public Drawable getDrawable(Context context, UserRecord item) {
+ if (item.isAddUser) {
+ return context.getDrawable(R.drawable.ic_add_circle_qs);
+ }
+ return context.getDrawable(R.drawable.ic_account_circle_qs);
+ }
}
public static final class UserRecord {
@@ -349,16 +415,22 @@
public final Bitmap picture;
public final boolean isGuest;
public final boolean isCurrent;
+ public final boolean isAddUser;
+ /** If true, the record is only visible to the owner and only when unlocked. */
+ public final boolean isRestricted;
- public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent) {
+ public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
+ boolean isAddUser, boolean isRestricted) {
this.info = info;
this.picture = picture;
this.isGuest = isGuest;
this.isCurrent = isCurrent;
+ this.isAddUser = isAddUser;
+ this.isRestricted = isRestricted;
}
public UserRecord copyWithIsCurrent(boolean _isCurrent) {
- return new UserRecord(info, picture, isGuest, _isCurrent);
+ return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
}
public String toString() {
@@ -367,17 +439,17 @@
if (info != null) {
sb.append("name=\"" + info.name + "\" id=" + info.id);
} else {
- sb.append("<add guest placeholder>");
+ if (isGuest) {
+ sb.append("<add guest placeholder>");
+ } else if (isAddUser) {
+ sb.append("<add user placeholder>");
+ }
}
- if (isGuest) {
- sb.append(" <isGuest>");
- }
- if (isCurrent) {
- sb.append(" <isCurrent>");
- }
- if (picture != null) {
- sb.append(" <hasPicture>");
- }
+ if (isGuest) sb.append(" <isGuest>");
+ if (isAddUser) sb.append(" <isAddUser>");
+ if (isCurrent) sb.append(" <isCurrent>");
+ if (picture != null) sb.append(" <hasPicture>");
+ if (isRestricted) sb.append(" <isRestricted>");
sb.append(')');
return sb.toString();
}
@@ -418,6 +490,13 @@
}
};
+ private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
+ @Override
+ public void onKeyguardChanged() {
+ notifyAdapters();
+ }
+ };
+
private final class ExitGuestDialog extends SystemUIDialog implements
DialogInterface.OnClickListener {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index d202036..3a63a79 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -24,6 +24,7 @@
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
@@ -44,7 +45,6 @@
import android.provider.Settings.Global;
import android.util.Log;
import android.util.SparseArray;
-import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -355,23 +355,8 @@
}
};
- // Change some window properties
final Window window = mDialog.getWindow();
- final LayoutParams lp = window.getAttributes();
- lp.token = null;
- // Offset from the top
- lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
- lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
- lp.format = PixelFormat.TRANSLUCENT;
- lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
- lp.gravity = Gravity.TOP;
- window.setAttributes(lp);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.requestFeature(Window.FEATURE_NO_TITLE);
- window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
- | LayoutParams.FLAG_NOT_TOUCH_MODAL
- | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | LayoutParams.FLAG_HARDWARE_ACCELERATED);
mDialog.setCanceledOnTouchOutside(true);
mDialog.setContentView(com.android.systemui.R.layout.volume_dialog);
mDialog.setOnDismissListener(new OnDismissListener() {
@@ -384,9 +369,24 @@
});
mDialog.create();
- // temporary workaround, until we support window-level shadows
- mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0x00000000));
+ final LayoutParams lp = window.getAttributes();
+ lp.token = null;
+ lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+ lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
+ lp.format = PixelFormat.TRANSLUCENT;
+ lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+ lp.setTitle(TAG);
+ window.setAttributes(lp);
+
+ updateWidth();
+
+ window.setBackgroundDrawable(new ColorDrawable(0x00000000));
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+ | LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | LayoutParams.FLAG_HARDWARE_ACCELERATED);
mView = window.findViewById(R.id.content);
mView.setOnTouchListener(new View.OnTouchListener() {
@Override
@@ -416,6 +416,19 @@
registerReceiver();
}
+ public void onConfigurationChanged(Configuration newConfig) {
+ updateWidth();
+ }
+
+ private void updateWidth() {
+ final Resources res = mContext.getResources();
+ final LayoutParams lp = mDialog.getWindow().getAttributes();
+ lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.notification_panel_width);
+ lp.gravity =
+ res.getInteger(com.android.systemui.R.integer.notification_panel_layout_gravity);
+ mDialog.getWindow().setAttributes(lp);
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("VolumePanel state:");
pw.print(" mTag="); pw.println(mTag);
@@ -1016,7 +1029,6 @@
int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
// when the stream is for remote playback, use -1 to reset the stream type evaluation
mAudioManager.forceVolumeControlStream(stream);
-
mDialog.show();
if (mCallback != null) {
mCallback.onVisible(true);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index cc351f9..04a3b88 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -3,6 +3,7 @@
import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.IRemoteVolumeController;
@@ -73,6 +74,14 @@
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mPanel != null) {
+ mPanel.onConfigurationChanged(newConfig);
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mPanel != null) {
mPanel.dump(fd, pw, args);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index e9d0c46..4315e0d 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3125,9 +3125,13 @@
// Apps hosting the AppWidget get to bind to a remote view service in the provider.
return true;
}
- if (mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET)
+ final int userId = UserHandle.getUserId(uid);
+ if ((widget.host.getUserId() == userId || (widget.provider != null
+ && widget.provider.getUserId() == userId))
+ && mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET)
== PackageManager.PERMISSION_GRANTED) {
- // Apps that can bind have access to all appWidgetIds.
+ // Apps that run in the same user as either the host or the provider and
+ // have the bind widget permission have access to the widget.
return true;
}
return false;
@@ -3187,14 +3191,7 @@
}
public boolean isHostInPackageForUid(Host host, int uid, String packageName) {
- if (UserHandle.getAppId(uid) == Process.myUid()) {
- // For a host that's in the system process, ignore the user id.
- return UserHandle.isSameApp(host.id.uid, uid)
- && host.id.packageName.equals(packageName);
- } else {
- return host.id.uid == uid
- && host.id.packageName.equals(packageName);
- }
+ return host.id.uid == uid && host.id.packageName.equals(packageName);
}
public boolean isProviderInPackageForUid(Provider provider, int uid,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ae2ef06..e0d4aad 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10585,14 +10585,16 @@
}
void startAppProblemLocked(ProcessRecord app) {
- if (app.userId == mCurrentUserId) {
- app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
- mContext, app.info.packageName, app.info.flags);
- } else {
- // If this app is not running under the current user, then we
- // can't give it a report button because that would require
- // launching the report UI under a different user.
- app.errorReportReceiver = null;
+ // If this app is not running under the current user, then we
+ // can't give it a report button because that would require
+ // launching the report UI under a different user.
+ app.errorReportReceiver = null;
+
+ for (int userId : mCurrentProfileIds) {
+ if (app.userId == userId) {
+ app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+ mContext, app.info.packageName, app.info.flags);
+ }
}
skipCurrentReceiverLocked(app);
}
@@ -17244,6 +17246,10 @@
Slog.w(TAG, "No user info for user #" + userId);
return false;
}
+ if (foreground && userInfo.isManagedProfile()) {
+ Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
+ return false;
+ }
if (foreground) {
mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 924d7aa..d67b8f1 100644
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -39,7 +39,7 @@
* <li>Gather "Vendor id" of all acknowledge devices
* </ol>
*/
-final class DeviceDiscoveryAction extends FeatureAction {
+final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
private static final String TAG = "DeviceDiscoveryAction";
// State in which the action is waiting for device polling.
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index c3c3fe1..d965caa 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -30,7 +30,7 @@
* <p>
* Package-private, accessed by {@link HdmiControlService} only.
*/
-final class DevicePowerStatusAction extends FeatureAction {
+final class DevicePowerStatusAction extends HdmiCecFeatureAction {
private static final String TAG = "DevicePowerStatusAction";
// State in which the action is waiting for <Report Power Status>.
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index e006e1c..ed37ead 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -33,7 +33,7 @@
* for a new active source. It does its best to wake up the target in standby mode
* before issuing the command >Set Stream path<.
*/
-final class DeviceSelectAction extends FeatureAction {
+final class DeviceSelectAction extends HdmiCecFeatureAction {
private static final String TAG = "DeviceSelect";
// Time in milliseconds we wait for the device power status to switch to 'Standby'
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
similarity index 82%
rename from services/core/java/com/android/server/hdmi/FeatureAction.java
rename to services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index b7b2f90..f32e660 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -29,21 +29,19 @@
/**
* Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
- *
- * <p>Many CEC/MHL features are accomplished by CEC devices on the bus exchanging
- * more than one command. {@link FeatureAction} represents the life cycle of the communication,
- * manages the state as the process progresses, and if necessary, returns the result
- * to the caller which initiates the action, through the callback given at the creation
- * of the object. All the actual action classes inherit FeatureAction.
- *
- * <p>More than one FeatureAction objects can be up and running simultaneously,
- * maintained by {@link HdmiCecLocalDevice}. Each action is passed a new command
- * arriving from the bus, and either consumes it if the command is what the action expects,
- * or yields it to other action.
- *
- * Declared as package private, accessed by {@link HdmiControlService} only.
+ * <p>
+ * Many CEC/MHL features are accomplished by CEC devices on the bus exchanging more than one
+ * command. {@link HdmiCecFeatureAction} represents the life cycle of the communication, manages the
+ * state as the process progresses, and if necessary, returns the result to the caller which
+ * initiates the action, through the callback given at the creation of the object. All the actual
+ * action classes inherit FeatureAction.
+ * <p>
+ * More than one FeatureAction objects can be up and running simultaneously, maintained by
+ * {@link HdmiCecLocalDevice}. Each action is passed a new command arriving from the bus, and either
+ * consumes it if the command is what the action expects, or yields it to other action. Declared as
+ * package private, accessed by {@link HdmiControlService} only.
*/
-abstract class FeatureAction {
+abstract class HdmiCecFeatureAction {
private static final String TAG = "FeatureAction";
// Timer handler message used for timeout event
@@ -61,9 +59,9 @@
// Timer that manages timeout events.
protected ActionTimer mActionTimer;
- private ArrayList<Pair<FeatureAction, Runnable>> mOnFinishedCallbacks;
+ private ArrayList<Pair<HdmiCecFeatureAction, Runnable>> mOnFinishedCallbacks;
- FeatureAction(HdmiCecLocalDevice source) {
+ HdmiCecFeatureAction(HdmiCecLocalDevice source) {
mSource = source;
mService = mSource.getService();
mActionTimer = createActionTimer(mService.getServiceLooper());
@@ -173,11 +171,11 @@
mService.sendCecCommand(cmd, callback);
}
- protected final void addAndStartAction(FeatureAction action) {
+ protected final void addAndStartAction(HdmiCecFeatureAction action) {
mSource.addAndStartAction(action);
}
- protected final <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+ protected final <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
return mSource.getActions(clazz);
}
@@ -191,16 +189,16 @@
*
* @param action
*/
- protected final void removeAction(FeatureAction action) {
+ protected final void removeAction(HdmiCecFeatureAction action) {
mSource.removeAction(action);
}
- protected final <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+ protected final <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) {
mSource.removeActionExcept(clazz, null);
}
- protected final <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
- final FeatureAction exception) {
+ protected final <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz,
+ final HdmiCecFeatureAction exception) {
mSource.removeActionExcept(clazz, exception);
}
@@ -233,7 +231,7 @@
removeAction(this);
}
if (mOnFinishedCallbacks != null) {
- for (Pair<FeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
+ for (Pair<HdmiCecFeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
if (actionCallbackPair.first.mState != STATE_NONE) {
actionCallbackPair.second.run();
}
@@ -269,7 +267,7 @@
getSourceAddress(), targetAddress));
}
- protected final void addOnFinishedCallback(FeatureAction action, Runnable runnable) {
+ protected final void addOnFinishedCallback(HdmiCecFeatureAction action, Runnable runnable) {
if (mOnFinishedCallbacks == null) {
mOnFinishedCallbacks = new ArrayList<>();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 18bfe32..be4c834 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -102,7 +102,7 @@
// A collection of FeatureAction.
// Note that access to this collection should happen in service thread.
- private final LinkedList<FeatureAction> mActions = new LinkedList<>();
+ private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>();
private final Handler mHandler = new Handler () {
@Override
@@ -250,7 +250,7 @@
@ServiceThreadOnly
private boolean dispatchMessageToAction(HdmiCecMessage message) {
assertRunOnServiceThread();
- for (FeatureAction action : mActions) {
+ for (HdmiCecFeatureAction action : mActions) {
if (action.processCommand(message)) {
return true;
}
@@ -486,7 +486,7 @@
}
@ServiceThreadOnly
- void addAndStartAction(final FeatureAction action) {
+ void addAndStartAction(final HdmiCecFeatureAction action) {
assertRunOnServiceThread();
if (mService.isPowerStandbyOrTransient()) {
Slog.w(TAG, "Skip the action during Standby: " + action);
@@ -498,9 +498,9 @@
// See if we have an action of a given type in progress.
@ServiceThreadOnly
- <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
+ <T extends HdmiCecFeatureAction> boolean hasAction(final Class<T> clazz) {
assertRunOnServiceThread();
- for (FeatureAction action : mActions) {
+ for (HdmiCecFeatureAction action : mActions) {
if (action.getClass().equals(clazz)) {
return true;
}
@@ -510,10 +510,10 @@
// Returns all actions matched with given class type.
@ServiceThreadOnly
- <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+ <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
assertRunOnServiceThread();
List<T> actions = Collections.<T>emptyList();
- for (FeatureAction action : mActions) {
+ for (HdmiCecFeatureAction action : mActions) {
if (action.getClass().equals(clazz)) {
if (actions.isEmpty()) {
actions = new ArrayList<T>();
@@ -525,12 +525,12 @@
}
/**
- * Remove the given {@link FeatureAction} object from the action queue.
+ * Remove the given {@link HdmiCecFeatureAction} object from the action queue.
*
- * @param action {@link FeatureAction} to remove
+ * @param action {@link HdmiCecFeatureAction} to remove
*/
@ServiceThreadOnly
- void removeAction(final FeatureAction action) {
+ void removeAction(final HdmiCecFeatureAction action) {
assertRunOnServiceThread();
action.finish(false);
mActions.remove(action);
@@ -539,19 +539,19 @@
// Remove all actions matched with the given Class type.
@ServiceThreadOnly
- <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+ <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) {
assertRunOnServiceThread();
removeActionExcept(clazz, null);
}
// Remove all actions matched with the given Class type besides |exception|.
@ServiceThreadOnly
- <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
- final FeatureAction exception) {
+ <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz,
+ final HdmiCecFeatureAction exception) {
assertRunOnServiceThread();
- Iterator<FeatureAction> iter = mActions.iterator();
+ Iterator<HdmiCecFeatureAction> iter = mActions.iterator();
while (iter.hasNext()) {
- FeatureAction action = iter.next();
+ HdmiCecFeatureAction action = iter.next();
if (action != exception && action.getClass().equals(clazz)) {
action.finish(false);
iter.remove();
@@ -698,9 +698,9 @@
// If all actions are not cleared in DEVICE_CLEANUP_TIMEOUT, enforce to finish them.
// onCleard will be called at the last action's finish method.
- Iterator<FeatureAction> iter = mActions.iterator();
+ Iterator<HdmiCecFeatureAction> iter = mActions.iterator();
while (iter.hasNext()) {
- FeatureAction action = iter.next();
+ HdmiCecFeatureAction action = iter.next();
action.finish(false);
iter.remove();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 7dc51a8..ae7fd82 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -140,7 +140,7 @@
if (physicalAddress != mService.getPhysicalAddress()) {
mIsActiveSource = false;
if (mService.isPowerOnOrTransient()) {
- mService.standby();
+ mService.nap();
}
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index 26071e6..433e93f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -28,8 +28,6 @@
public final class HdmiCecMessage {
public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
- private static final int MAX_MESSAGE_PARAM_LENGTH = 14;
-
private final int mSource;
private final int mDestination;
@@ -43,12 +41,6 @@
mSource = source;
mDestination = destination;
mOpcode = opcode & 0xFF;
-
- if (params.length > MAX_MESSAGE_PARAM_LENGTH) {
- throw new IllegalArgumentException(
- "Param length should be at most 13 but current param length is "
- + params.length);
- }
mParams = Arrays.copyOf(params, params.length);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 29a73d0..4c88ce0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -250,6 +250,9 @@
return true;
}
int path = HdmiUtils.twoBytesToInt(params, offset);
+ if (path != Constants.INVALID_PHYSICAL_ADDRESS && path == mService.getPhysicalAddress()) {
+ return true;
+ }
int portId = mService.pathToPortId(path);
if (portId == Constants.INVALID_PORT_ID) {
return false;
@@ -259,10 +262,10 @@
/**
* Check if the given type is valid. A valid type is one of the actual logical device types
- * defined in the standard ({@link HdmiCecDeviceInfo#DEVICE_TV},
- * {@link HdmiCecDeviceInfo#DEVICE_PLAYBACK}, {@link HdmiCecDeviceInfo#DEVICE_TUNER},
- * {@link HdmiCecDeviceInfo#DEVICE_RECORDER}, and
- * {@link HdmiCecDeviceInfo#DEVICE_AUDIO_SYSTEM}).
+ * defined in the standard ({@link HdmiDeviceInfo#DEVICE_TV},
+ * {@link HdmiDeviceInfo#DEVICE_PLAYBACK}, {@link HdmiDeviceInfo#DEVICE_TUNER},
+ * {@link HdmiDeviceInfo#DEVICE_RECORDER}, and
+ * {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}).
*
* @param type device type
* @return true if the given type is valid
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3017d2d..cccc44c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -517,13 +517,20 @@
@ServiceThreadOnly
void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) {
assertRunOnServiceThread();
- mCecController.sendCommand(command, callback);
+ if (mMessageValidator.isValid(command)) {
+ mCecController.sendCommand(command, callback);
+ } else {
+ Slog.e(TAG, "Invalid message type:" + command);
+ if (callback != null) {
+ callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
+ }
+ }
}
@ServiceThreadOnly
void sendCecCommand(HdmiCecMessage command) {
assertRunOnServiceThread();
- mCecController.sendCommand(command, null);
+ sendCecCommand(command, null);
}
/**
@@ -1444,6 +1451,11 @@
// the intent, the sequence will continue at onStandby().
}
+ void nap() {
+ PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
+ pm.nap(SystemClock.uptimeMillis());
+ }
+
@ServiceThreadOnly
private void onWakeUp() {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 8fc0bbc..51e68b6 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -33,7 +33,7 @@
* For other devices, keep 15 secs period.
*/
// Seq #3
-final class HotplugDetectionAction extends FeatureAction {
+final class HotplugDetectionAction extends HdmiCecFeatureAction {
private static final String TAG = "HotPlugDetectionAction";
private static final int POLLING_INTERVAL_MS = 5000;
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 8154204..a5fdbea 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -33,7 +33,7 @@
*
* <p>Package-private, accessed by {@link HdmiControlService} only.
*/
-final class NewDeviceAction extends FeatureAction {
+final class NewDeviceAction extends HdmiCecFeatureAction {
private static final String TAG = "NewDeviceAction";
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 752cc37..7db991a 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -28,7 +28,7 @@
* <p>
* Package-private, accessed by {@link HdmiControlService} only.
*/
-final class OneTouchPlayAction extends FeatureAction {
+final class OneTouchPlayAction extends HdmiCecFeatureAction {
private static final String TAG = "OneTouchPlayAction";
// State in which the action is waiting for <Report Power Status>. In normal situation
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index befc640..39c0d7f 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -29,7 +29,7 @@
/**
* Feature action that performs one touch record.
*/
-public class OneTouchRecordAction extends FeatureAction {
+public class OneTouchRecordAction extends HdmiCecFeatureAction {
private static final String TAG = "OneTouchRecordAction";
// Timer out for waiting <Record Status> 120s
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index 3b1ad53..9c530a3 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -23,7 +23,7 @@
/**
* Base feature action class for <Request ARC Initiation>/<Request ARC Termination>.
*/
-abstract class RequestArcAction extends FeatureAction {
+abstract class RequestArcAction extends HdmiCecFeatureAction {
private static final String TAG = "RequestArcAction";
// State in which waits for ARC response.
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index dbf1961..435ab7f 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -38,7 +38,7 @@
* <li> Routing at CEC enable time
* </ul>
*/
-final class RoutingControlAction extends FeatureAction {
+final class RoutingControlAction extends HdmiCecFeatureAction {
private static final String TAG = "RoutingControlAction";
// State in which we wait for <Routing Information> to arrive. If timed out, we use the
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index ca2826e..9f09eb4 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -32,7 +32,7 @@
*
* <p>Package-private, accessed by {@link HdmiControlService} only.
*/
-final class SendKeyAction extends FeatureAction {
+final class SendKeyAction extends HdmiCecFeatureAction {
private static final String TAG = "SendKeyAction";
// State in which the action is at work. The state is set in {@link #start()} and
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 6104eb2..9f7f98a 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -24,7 +24,7 @@
* Once TV gets <Initiate ARC>, TV sends <Report ARC Initiated> to AV Receiver.
* If it fails or it gets <Terminate ARC>, TV just disables ARC.
*/
-final class SetArcTransmissionStateAction extends FeatureAction {
+final class SetArcTransmissionStateAction extends HdmiCecFeatureAction {
private static final String TAG = "SetArcTransmissionStateAction";
// State in which the action sent <Rerpot Arc Initiated> and
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index 057f9ba..7e45a99 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -28,7 +28,7 @@
/**
* Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
*/
-abstract class SystemAudioAction extends FeatureAction {
+abstract class SystemAudioAction extends HdmiCecFeatureAction {
private static final String TAG = "SystemAudioAction";
// Transient state to differentiate with STATE_NONE where the on-finished callback
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 137cada..3653aac 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -22,7 +22,7 @@
* Action to initiate system audio once AVR is detected on Device discovery action.
*/
// Seq #27
-final class SystemAudioAutoInitiationAction extends FeatureAction {
+final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction {
private final int mAvrAddress;
// State that waits for <System Audio Mode Status> once send
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 1066204..bfcda50 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -27,7 +27,7 @@
/**
* Action to update audio status (volume or mute) of audio amplifier
*/
-final class SystemAudioStatusAction extends FeatureAction {
+final class SystemAudioStatusAction extends HdmiCecFeatureAction {
private static final String TAG = "SystemAudioStatusAction";
// State that waits for <ReportAudioStatus>.
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 1a179e6..8fc0182 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -31,7 +31,7 @@
/**
* Feature action that performs timer recording.
*/
-public class TimerRecordingAction extends FeatureAction {
+public class TimerRecordingAction extends HdmiCecFeatureAction {
private static final String TAG = "TimerRecordingAction";
// Timer out for waiting <Timer Status> 120s.
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index e32b792..01c6f3e 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -28,7 +28,7 @@
* from Audio Receiver(AVR). If TV receives no <Report Audio Status> from AVR, this action
* will be finished in {@link #IRT_MS} * {@link #VOLUME_CHANGE_TIMEOUT_MAX_COUNT} (ms).
*/
-final class VolumeControlAction extends FeatureAction {
+final class VolumeControlAction extends HdmiCecFeatureAction {
private static final String TAG = "VolumeControlAction";
private static final int VOLUME_MUTE = 101;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 9ac90dc..14457ec 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -74,7 +74,7 @@
static final boolean DEBUG = true;
/** The number of concurrent jobs we run at one time. */
private static final int MAX_JOB_CONTEXTS_COUNT = 3;
- static final String TAG = "JobManagerService";
+ static final String TAG = "JobSchedulerService";
/** Master list of jobs. */
final JobStore mJobs;
@@ -88,6 +88,11 @@
*/
static final int MIN_IDLE_COUNT = 1;
/**
+ * Minimum # of charging jobs that must be ready in order to force the JMS to schedule things
+ * early.
+ */
+ static final int MIN_CHARGING_COUNT = 1;
+ /**
* Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
* things early.
*/
@@ -95,8 +100,9 @@
/**
* Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
* some work early.
+ * This is correlated with the amount of batching we'll be able to do.
*/
- static final int MIN_READY_JOBS_COUNT = 4;
+ static final int MIN_READY_JOBS_COUNT = 2;
/**
* Track Services that have currently active or pending jobs. The index is provided by
@@ -546,7 +552,8 @@
*/
private void maybeQueueReadyJobsForExecutionH() {
synchronized (mJobs) {
- int idleCount = 0;
+ int chargingCount = 0;
+ int idleCount = 0;
int backoffCount = 0;
int connectivityCount = 0;
List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
@@ -563,17 +570,34 @@
if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
connectivityCount++;
}
+ if (job.hasChargingConstraint()) {
+ chargingCount++;
+ }
runnableJobs.add(job);
} else if (isReadyToBeCancelledLocked(job)) {
stopJobOnServiceContextLocked(job);
}
}
- if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
+ if (backoffCount > 0 ||
+ idleCount >= MIN_IDLE_COUNT ||
connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+ chargingCount >= MIN_CHARGING_COUNT ||
runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
+ if (DEBUG) {
+ Slog.d(TAG, "maybeQueueReadyJobsForExecutionH: Running jobs.");
+ }
for (int i=0; i<runnableJobs.size(); i++) {
mPendingJobs.add(runnableJobs.get(i));
}
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "maybeQueueReadyJobsForExecutionH: Not running anything.");
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
+ connectivityCount + " charging=" + chargingCount + " tot=" +
+ runnableJobs.size());
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 2213934..7b71027 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -113,12 +113,13 @@
public IdlenessTracker() {
mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(ACTION_TRIGGER_IDLE);
- intent.setComponent(new ComponentName(mContext, this.getClass()));
+ Intent intent = new Intent(ACTION_TRIGGER_IDLE)
+ .setPackage("android")
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- // at boot we presume that the user has just "interacted" with the
- // device in some meaningful way
+ // At boot we presume that the user has just "interacted" with the
+ // device in some meaningful way.
mIdle = false;
}
@@ -163,9 +164,11 @@
// when the screen goes off or dreaming starts, we schedule the
// alarm that will tell us when we have decided the device is
// truly idle.
- long when = SystemClock.elapsedRealtime() + INACTIVITY_IDLE_THRESHOLD;
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long when = nowElapsed + INACTIVITY_IDLE_THRESHOLD;
if (DEBUG) {
- Slog.v(TAG, "Scheduling idle : " + action + " when=" + when);
+ Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when="
+ + when);
}
mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 8b0a46d..b261ef5 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -212,6 +212,34 @@
return execute(builder.toString());
}
+ public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
+ String instructionSet) {
+ StringBuilder builder = new StringBuilder("patchoat");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(' ');
+ builder.append(pkgName);
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
+ public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("patchoat");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(" *"); // No pkgName arg present
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index df1269ee..4bf6636 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1420,11 +1420,18 @@
}
try {
- if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
+ byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
+ instructionSet,
+ false);
+ if (dexoptRequired != DexFile.UP_TO_DATE) {
alreadyDexOpted.add(lib);
// The list of "shared libraries" we have at this point is
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+ if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+ } else {
+ mInstaller.patchoat(lib, Process.SYSTEM_UID, true, instructionSet);
+ }
didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
@@ -1471,9 +1478,15 @@
continue;
}
try {
- if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
+ byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
+ instructionSet,
+ false);
+ if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
didDexOptLibraryOrTool = true;
+ } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
+ mInstaller.patchoat(path, Process.SYSTEM_UID, true, instructionSet);
+ didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
@@ -4625,9 +4638,14 @@
}
try {
- final boolean isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
+ // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+ // patckage or the one we find does not match the image checksum (i.e. it was
+ // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+ // odex file and it matches the checksum of the image but not its base address,
+ // meaning we need to move it.
+ final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
pkg.packageName, instructionSet, defer);
- if (forceDex || (!defer && isDexOptNeeded)) {
+ if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
Log.i(TAG, "Running dexopt on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + instructionSet);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
@@ -4643,12 +4661,27 @@
performedDexOpt = true;
pkg.mDexOptPerformed.add(instructionSet);
}
+ } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
+ Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
+ pkg.packageName, instructionSet);
+
+ if (ret < 0) {
+ // Don't bother running patchoat again if we failed, it will probably
+ // just result in an error again. Also, don't bother dexopting for other
+ // paths & ISAs.
+ return DEX_OPT_FAILED;
+ } else {
+ performedDexOpt = true;
+ pkg.mDexOptPerformed.add(instructionSet);
+ }
}
// We're deciding to defer a needed dexopt. Don't bother dexopting for other
// paths and instruction sets. We'll deal with them all together when we process
// our list of deferred dexopts.
- if (defer && isDexOptNeeded) {
+ if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
if (mDeferredDexOpt == null) {
mDeferredDexOpt = new HashSet<PackageParser.Package>();
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index ee20b3c..0523af7 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -93,7 +93,6 @@
mTrusted = true;
mMessage = (CharSequence) msg.obj;
boolean initiatedByUser = msg.arg1 != 0;
- // TODO: Handle initiatedByUser.
long durationMs = msg.getData().getLong(DATA_DURATION);
if (durationMs > 0) {
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
@@ -102,7 +101,7 @@
mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
(mMessage != null ? mMessage.toString() : null),
durationMs, initiatedByUser);
- mTrustManagerService.updateTrust(mUserId);
+ mTrustManagerService.updateTrust(mUserId, initiatedByUser);
break;
case MSG_TRUST_TIMEOUT:
if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
@@ -115,7 +114,7 @@
if (msg.what == MSG_REVOKE_TRUST) {
mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
}
- mTrustManagerService.updateTrust(mUserId);
+ mTrustManagerService.updateTrust(mUserId, false);
break;
case MSG_RESTART_TIMEOUT:
unbind();
@@ -130,7 +129,7 @@
if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged "
+ "enabled features: " + mName);
mTrustDisabledByDpm = false;
- mTrustManagerService.updateTrust(mUserId);
+ mTrustManagerService.updateTrust(mUserId, false);
}
} else {
if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
@@ -144,7 +143,7 @@
mMessage = null;
}
mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
- mTrustManagerService.updateTrust(mUserId);
+ mTrustManagerService.updateTrust(mUserId, false);
break;
}
}
@@ -282,7 +281,7 @@
}
if (mTrustDisabledByDpm != trustDisabled) {
mTrustDisabledByDpm = trustDisabled;
- mTrustManagerService.updateTrust(mUserId);
+ mTrustManagerService.updateTrust(mUserId, false);
}
return trustDisabled;
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d3b8d5d..badead6 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -148,13 +148,13 @@
private void updateTrustAll() {
List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
for (UserInfo userInfo : userInfos) {
- updateTrust(userInfo.id);
+ updateTrust(userInfo.id, false);
}
}
- public void updateTrust(int userId) {
+ public void updateTrust(int userId, boolean initiatedByUser) {
dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId);
- dispatchOnTrustChanged(aggregateIsTrusted(userId), userId);
+ dispatchOnTrustChanged(aggregateIsTrusted(userId), userId, initiatedByUser);
}
void refreshAgentList() {
@@ -272,7 +272,7 @@
}
}
if (trustMayHaveChanged) {
- updateTrust(userId);
+ updateTrust(userId, false);
}
refreshAgentList();
}
@@ -375,7 +375,7 @@
if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
mUserHasAuthenticatedSinceBoot.put(userId, true);
- updateTrust(userId);
+ updateTrust(userId, false);
}
}
@@ -386,7 +386,7 @@
updateTrustAll();
} else {
mUserHasAuthenticatedSinceBoot.put(userId, false);
- updateTrust(userId);
+ updateTrust(userId, false);
}
}
@@ -410,10 +410,11 @@
}
}
- private void dispatchOnTrustChanged(boolean enabled, int userId) {
+ private void dispatchOnTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
+ if (!enabled) initiatedByUser = false;
for (int i = 0; i < mTrustListeners.size(); i++) {
try {
- mTrustListeners.get(i).onTrustChanged(enabled, userId);
+ mTrustListeners.get(i).onTrustChanged(enabled, userId, initiatedByUser);
} catch (DeadObjectException e) {
Slog.d(TAG, "Removing dead TrustListener.");
mTrustListeners.remove(i);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 4ed7cb7..c095905 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1074,39 +1074,50 @@
try {
synchronized (mLock) {
UserState userState = getUserStateLocked(resolvedUserId);
- if (sessionToken == userState.mainSessionToken) {
+ if (userState.mainSessionToken == sessionToken) {
return;
}
- SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
- resolvedUserId);
- ServiceState serviceState = getServiceStateLocked(
- sessionState.mInfo.getComponent(), resolvedUserId);
- ITvInputSession session = getSessionLocked(sessionState);
+ SessionState newMainSessionState = getSessionStateLocked(
+ sessionToken, callingUid, resolvedUserId);
+ if (newMainSessionState.mHardwareSessionToken != null) {
+ newMainSessionState = getSessionStateLocked(
+ newMainSessionState.mHardwareSessionToken,
+ Process.SYSTEM_UID, resolvedUserId);
+ }
+ ServiceState newMainServiceState = getServiceStateLocked(
+ newMainSessionState.mInfo.getComponent(), resolvedUserId);
+ ITvInputSession newMainSession = getSessionLocked(newMainSessionState);
- ServiceState prevMainServiceState = null;
- ITvInputSession prevMainSession = null;
+ ServiceState oldMainServiceState = null;
+ ITvInputSession oldMainSession = null;
if (userState.mainSessionToken != null) {
- SessionState prevMainSessionState = getSessionStateLocked(
+ SessionState oldMainSessionState = getSessionStateLocked(
userState.mainSessionToken, Process.SYSTEM_UID, resolvedUserId);
- prevMainServiceState = getServiceStateLocked(
- prevMainSessionState.mInfo.getComponent(), resolvedUserId);
- prevMainSession = getSessionLocked(prevMainSessionState);
+ if (oldMainSessionState.mHardwareSessionToken != null) {
+ oldMainSessionState = getSessionStateLocked(
+ oldMainSessionState.mHardwareSessionToken,
+ Process.SYSTEM_UID, resolvedUserId);
+ }
+ oldMainServiceState = getServiceStateLocked(
+ oldMainSessionState.mInfo.getComponent(), resolvedUserId);
+ oldMainSession = getSessionLocked(oldMainSessionState);
}
userState.mainSessionToken = sessionToken;
- // Inform the new main session first. See {@link TvInputService#onSetMain}.
- if (serviceState.mIsHardware) {
+ // Inform the new main session first.
+ // See {@link TvInputService#onSetMainSession}.
+ if (newMainServiceState.mIsHardware) {
try {
- session.setMainSession(true);
+ newMainSession.setMainSession(true);
} catch (RemoteException e) {
Slog.e(TAG, "error in setMainSession", e);
}
}
- if (prevMainSession != null && prevMainServiceState.mIsHardware) {
+ if (oldMainSession != null && oldMainServiceState.mIsHardware) {
try {
- prevMainSession.setMainSession(false);
+ oldMainSession.setMainSession(false);
} catch (RemoteException e) {
Slog.e(TAG, "error in setMainSession", e);
}
@@ -1522,6 +1533,34 @@
}
@Override
+ public boolean isSingleSessionActive(int userId) throws RemoteException {
+ final long identity = Binder.clearCallingIdentity();
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "isSingleSessionActive");
+ try {
+ synchronized (mLock) {
+ UserState userState = getUserStateLocked(resolvedUserId);
+ if (userState.sessionStateMap.size() == 1) {
+ return true;
+ }
+ else if (userState.sessionStateMap.size() == 2) {
+ SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
+ new SessionState[0]);
+ // Check if there is a wrapper input.
+ if (sessionStates[0].mHardwareSessionToken != null
+ || sessionStates[1].mHardwareSessionToken != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
@SuppressWarnings("resource")
protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
@@ -1644,6 +1683,7 @@
}
pw.decreaseIndent();
+ pw.println("mainSessionToken: " + userState.mainSessionToken);
pw.decreaseIndent();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7a7eaf1..fc96991 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2315,30 +2315,39 @@
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
- int count = 0;
+ ActiveAdmin admin = (who != null) ? getActiveAdminUncheckedLocked(who, userHandle)
+ : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+ return admin != null ? admin.maximumFailedPasswordsForWipe : 0;
+ }
+ }
- if (who != null) {
- ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
- return admin != null ? admin.maximumFailedPasswordsForWipe : count;
- }
+ /**
+ * Returns the admin with the strictest policy on maximum failed passwords for this user and all
+ * profiles that are visible from this user. If the policy for the primary and any other profile
+ * are equal, it returns the admin for the primary profile.
+ * Returns {@code null} if none of them have that policy set.
+ */
+ private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(int userHandle) {
+ int count = 0;
+ ActiveAdmin strictestAdmin = null;
+ for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+ DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+ for (ActiveAdmin admin : policy.mAdminList) {
+ if (admin.maximumFailedPasswordsForWipe ==
+ ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
+ continue; // No max number of failed passwords policy set for this profile.
+ }
- // Return strictest policy for this user and profiles that are visible from this user.
- List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
- for (UserInfo userInfo : profiles) {
- DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
- final int N = policy.mAdminList.size();
- for (int i=0; i<N; i++) {
- ActiveAdmin admin = policy.mAdminList.get(i);
- if (count == 0) {
- count = admin.maximumFailedPasswordsForWipe;
- } else if (admin.maximumFailedPasswordsForWipe != 0
- && count > admin.maximumFailedPasswordsForWipe) {
- count = admin.maximumFailedPasswordsForWipe;
- }
+ // We always favor the primary profile if several profiles have the same value set.
+ if (count == 0 ||
+ count > admin.maximumFailedPasswordsForWipe ||
+ (userInfo.isPrimary() && count >= admin.maximumFailedPasswordsForWipe)) {
+ count = admin.maximumFailedPasswordsForWipe;
+ strictestAdmin = admin;
}
}
- return count;
}
+ return strictestAdmin;
}
public boolean resetPassword(String password, int flags, int userHandle) {
@@ -2713,7 +2722,9 @@
public void run() {
try {
ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
- mUserManager.removeUser(userHandle);
+ if (!mUserManager.removeUser(userHandle)) {
+ Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
+ }
} catch (RemoteException re) {
// Shouldn't happen
}
@@ -2837,9 +2848,15 @@
policy.mFailedPasswordAttempts++;
saveSettingsLocked(userHandle);
if (mHasFeature) {
- int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+ ActiveAdmin strictestAdmin =
+ getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+ int max = strictestAdmin != null
+ ? strictestAdmin.maximumFailedPasswordsForWipe : 0;
if (max > 0 && policy.mFailedPasswordAttempts >= max) {
- wipeDeviceOrUserLocked(0, userHandle);
+ // Wipe the user/profile associated with the policy that was violated. This
+ // is not necessarily calling user: if the policy that fired was from a
+ // managed profile rather than the main user profile, we wipe former only.
+ wipeDeviceOrUserLocked(0, strictestAdmin.getUserHandle().getIdentifier());
}
sendAdminCommandToSelfAndProfilesLocked(
DeviceAdminReceiver.ACTION_PASSWORD_FAILED,