summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManager.java12
-rw-r--r--core/java/android/app/ActivityManagerNative.java52
-rw-r--r--core/java/android/app/ActivityThread.java18
-rw-r--r--core/java/android/app/ContextImpl.java33
-rw-r--r--core/java/android/app/IActivityManager.java11
-rw-r--r--core/java/android/app/Notification.java11
-rw-r--r--core/java/android/app/PendingIntent.java61
-rw-r--r--core/java/android/app/TaskStackBuilder.java26
-rwxr-xr-xcore/java/android/app/admin/DevicePolicyManager.java176
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl96
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java10
-rw-r--r--core/java/android/content/ContentResolver.java22
-rw-r--r--core/java/android/content/ContentService.java154
-rw-r--r--core/java/android/content/Context.java71
-rw-r--r--core/java/android/content/IContentService.aidl22
-rw-r--r--core/java/android/content/Intent.java14
-rw-r--r--core/java/android/content/IntentSender.java20
-rw-r--r--core/java/android/content/pm/PackageManager.java6
-rw-r--r--core/java/android/content/pm/PackageUserState.java1
-rw-r--r--core/java/android/content/res/Configuration.java4
-rwxr-xr-xcore/java/android/content/res/Resources.java2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java34
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java25
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl6
-rw-r--r--core/java/android/hardware/display/WifiDisplay.java38
-rw-r--r--core/java/android/hardware/display/WifiDisplayStatus.java109
-rw-r--r--core/java/android/net/CaptivePortalTracker.java2
-rw-r--r--core/java/android/net/NetworkStats.java5
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java35
-rw-r--r--core/java/android/net/http/X509TrustManagerExtensions.java66
-rw-r--r--core/java/android/os/Environment.java25
-rw-r--r--core/java/android/os/IUserManager.aidl4
-rw-r--r--core/java/android/os/UserManager.java37
-rw-r--r--core/java/android/provider/Settings.java31
-rw-r--r--core/java/android/service/dreams/Dream.java250
-rw-r--r--core/java/android/service/dreams/DreamManagerService.java247
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl2
-rw-r--r--core/java/android/text/TextDirectionHeuristics.java3
-rw-r--r--core/java/android/text/TextUtils.java57
-rw-r--r--core/java/android/text/format/DateFormat.java63
-rw-r--r--core/java/android/text/format/DateUtils.java68
-rw-r--r--core/java/android/text/format/Time.java28
-rw-r--r--core/java/android/util/LocaleUtil.java84
-rwxr-xr-xcore/java/android/util/PropertyValueModel.java143
-rwxr-xr-xcore/java/android/util/ValueModel.java74
-rw-r--r--core/java/android/view/FocusFinder.java2
-rw-r--r--core/java/android/view/GLES20Canvas.java2
-rw-r--r--core/java/android/view/GLES20RenderLayer.java18
-rw-r--r--core/java/android/view/GLES20TextureLayer.java3
-rw-r--r--core/java/android/view/Gravity.java12
-rw-r--r--core/java/android/view/HardwareLayer.java3
-rw-r--r--core/java/android/view/HardwareRenderer.java31
-rw-r--r--core/java/android/view/View.java195
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/android/view/VolumePanel.java1
-rw-r--r--core/java/android/view/Window.java7
-rw-r--r--core/java/android/view/WindowManagerPolicy.java10
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java1
-rw-r--r--core/java/android/webkit/WebViewCore.java8
-rwxr-xr-xcore/java/android/widget/AppSecurityPermissions.java15
-rw-r--r--core/java/android/widget/CheckBox.java23
-rw-r--r--core/java/android/widget/EditText.java23
-rw-r--r--core/java/android/widget/Editor.java14
-rw-r--r--core/java/android/widget/ListPopupWindow.java4
-rw-r--r--core/java/android/widget/SeekBar.java20
-rwxr-xr-xcore/java/android/widget/ValueEditor.java53
-rw-r--r--core/java/com/android/internal/app/AlertController.java16
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuView.java54
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java157
69 files changed, 1650 insertions, 1281 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 06f79e7..0eda6b4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -864,7 +864,17 @@ public class ActivityManager {
return null;
}
}
-
+
+ /** @hide */
+ public Bitmap getTaskTopThumbnail(int id) throws SecurityException {
+ try {
+ return ActivityManagerNative.getDefault().getTaskTopThumbnail(id);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return null;
+ }
+ }
+
/**
* Flag for {@link #moveTaskToFront(int, int)}: also move the "home"
* activity along with the task, so it is positioned immediately behind
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index eae3b1f..8436b2c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -404,6 +404,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case ACTIVITY_RESUMED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ activityResumed(token);
+ reply.writeNoException();
+ return true;
+ }
+
case ACTIVITY_PAUSED_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -490,7 +498,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeTypedList(list);
return true;
}
-
+
case GET_TASK_THUMBNAILS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int id = data.readInt();
@@ -504,7 +512,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
}
return true;
}
-
+
+ case GET_TASK_TOP_THUMBNAIL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int id = data.readInt();
+ Bitmap bm = getTaskTopThumbnail(id);
+ reply.writeNoException();
+ if (bm != null) {
+ reply.writeInt(1);
+ bm.writeToParcel(reply, 0);
+ } else {
+ reply.writeInt(0);
+ }
+ return true;
+ }
+
case GET_SERVICES_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int maxNum = data.readInt();
@@ -2152,6 +2174,17 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+ public void activityResumed(IBinder token) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(ACTIVITY_RESUMED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
public void activityPaused(IBinder token) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -2288,6 +2321,21 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return bm;
}
+ public Bitmap getTaskTopThumbnail(int id) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(id);
+ mRemote.transact(GET_TASK_TOP_THUMBNAIL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Bitmap bm = null;
+ if (reply.readInt() != 0) {
+ bm = Bitmap.CREATOR.createFromParcel(reply);
+ }
+ data.recycle();
+ reply.recycle();
+ return bm;
+ }
public List getServices(int maxNum, int flags) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cb4d4a1..9b82f2a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1245,7 +1245,7 @@ public final class ActivityThread {
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
handleResumeActivity((IBinder)msg.obj, true,
- msg.arg1 != 0);
+ msg.arg1 != 0, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SEND_RESULT:
@@ -2175,7 +2175,8 @@ public final class ActivityThread {
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
- handleResumeActivity(r.token, false, r.isForward);
+ handleResumeActivity(r.token, false, r.isForward,
+ !r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out
@@ -2684,7 +2685,8 @@ public final class ActivityThread {
r.mPendingRemoveWindowManager = null;
}
- final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
+ final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
+ boolean reallyResume) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
@@ -2781,6 +2783,14 @@ public final class ActivityThread {
}
r.onlyLocalRequest = false;
+ // Tell the activity manager we have resumed.
+ if (reallyResume) {
+ try {
+ ActivityManagerNative.getDefault().activityResumed(token);
+ } catch (RemoteException ex) {
+ }
+ }
+
} else {
// If an exception was thrown when trying to resume, then
// just end this activity.
@@ -2865,7 +2875,7 @@ public final class ActivityThread {
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
-
+
// Tell the activity manager we have paused.
try {
ActivityManagerNative.getDefault().activityPaused(token);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 92104fa..56b745f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -129,32 +129,33 @@ class ReceiverRestrictedContext extends ContextWrapper {
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
- throw new ReceiverCallNotAllowedException(
- "IntentReceiver components are not allowed to register to receive intents");
- //ex.fillInStackTrace();
- //Log.e("IntentReceiver", ex.getMessage(), ex);
- //return mContext.registerReceiver(receiver, filter, broadcastPermission,
- // scheduler);
+ if (receiver == null) {
+ // Allow retrieving current sticky broadcast; this is safe since we
+ // aren't actually registering a receiver.
+ return super.registerReceiver(null, filter, broadcastPermission, scheduler);
+ } else {
+ throw new ReceiverCallNotAllowedException(
+ "BroadcastReceiver components are not allowed to register to receive intents");
+ }
}
@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
- throw new ReceiverCallNotAllowedException(
- "IntentReceiver components are not allowed to register to receive intents");
- //ex.fillInStackTrace();
- //Log.e("IntentReceiver", ex.getMessage(), ex);
- //return mContext.registerReceiver(receiver, filter, broadcastPermission,
- // scheduler);
+ if (receiver == null) {
+ // Allow retrieving current sticky broadcast; this is safe since we
+ // aren't actually registering a receiver.
+ return super.registerReceiverAsUser(null, user, filter, broadcastPermission, scheduler);
+ } else {
+ throw new ReceiverCallNotAllowedException(
+ "BroadcastReceiver components are not allowed to register to receive intents");
+ }
}
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
throw new ReceiverCallNotAllowedException(
- "IntentReceiver components are not allowed to bind to services");
- //ex.fillInStackTrace();
- //Log.e("IntentReceiver", ex.getMessage(), ex);
- //return mContext.bindService(service, interfaceName, conn, flags);
+ "BroadcastReceiver components are not allowed to bind to services");
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9ef375a..d6ebc9b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -87,19 +87,15 @@ public interface IActivityManager extends IInterface {
String resultData, Bundle map, String requiredPermission,
boolean serialized, boolean sticky, int userId) throws RemoteException;
public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
- /* oneway */
public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
public void attachApplication(IApplicationThread app) throws RemoteException;
- /* oneway */
+ public void activityResumed(IBinder token) throws RemoteException;
public void activityIdle(IBinder token, Configuration config,
boolean stopProfiling) throws RemoteException;
public void activityPaused(IBinder token) throws RemoteException;
- /* oneway */
public void activityStopped(IBinder token, Bundle state,
Bitmap thumbnail, CharSequence description) throws RemoteException;
- /* oneway */
public void activitySlept(IBinder token) throws RemoteException;
- /* oneway */
public void activityDestroyed(IBinder token) throws RemoteException;
public String getCallingPackage(IBinder token) throws RemoteException;
public ComponentName getCallingActivity(IBinder token) throws RemoteException;
@@ -108,6 +104,7 @@ public interface IActivityManager extends IInterface {
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException;
public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException;
+ public Bitmap getTaskTopThumbnail(int taskId) throws RemoteException;
public List getServices(int maxNum, int flags) throws RemoteException;
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
throws RemoteException;
@@ -496,7 +493,7 @@ public interface IActivityManager extends IInterface {
int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
-
+ int ACTIVITY_RESUMED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
int GOING_TO_SLEEP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
int WAKING_UP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
@@ -552,7 +549,7 @@ public interface IActivityManager extends IInterface {
int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
-
+ int GET_TASK_TOP_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cb83dc2..7896450 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1923,6 +1923,7 @@ public class Notification implements Parcelable
contentView.setViewVisibility(rowId, View.GONE);
}
+
int i=0;
while (i < mTexts.size() && i < rowIds.length) {
CharSequence str = mTexts.get(i);
@@ -1933,11 +1934,11 @@ public class Notification implements Parcelable
i++;
}
- if (mTexts.size() > rowIds.length) {
- contentView.setViewVisibility(R.id.inbox_more, View.VISIBLE);
- } else {
- contentView.setViewVisibility(R.id.inbox_more, View.GONE);
- }
+ contentView.setViewVisibility(R.id.inbox_end_pad,
+ mTexts.size() > 0 ? View.VISIBLE : View.GONE);
+
+ contentView.setViewVisibility(R.id.inbox_more,
+ mTexts.size() > rowIds.length ? View.VISIBLE : View.GONE);
return contentView;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index a3c1838..8fb6948 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -32,8 +32,8 @@ import android.util.AndroidException;
/**
* A description of an Intent and target action to perform with it. Instances
- * of this class are created with {@link #getActivity},
- * {@link #getBroadcast}, {@link #getService}; the returned object can be
+ * of this class are created with {@link #getActivity}, {@link #getActivities},
+ * {@link #getBroadcast}, and {@link #getService}; the returned object can be
* handed to other applications so that they can perform the action you
* described on your behalf at a later time.
*
@@ -54,6 +54,34 @@ import android.util.AndroidException;
* categories, and components, and same flags), it will receive a PendingIntent
* representing the same token if that is still valid, and can thus call
* {@link #cancel} to remove it.
+ *
+ * <p>Because of this behavior, it is important to know when two Intents
+ * are considered to be the same for purposes of retrieving a PendingIntent.
+ * A common mistake people make is to create multiple PendingIntent objects
+ * with Intents that only vary in their "extra" contents, expecting to get
+ * a different PendingIntent each time. This does <em>not</em> happen. The
+ * parts of the Intent that are used for matching are the same ones defined
+ * by {@link Intent#filterEquals(Intent) Intent.filterEquals}. If you use two
+ * Intent objects that are equivalent as per
+ * {@link Intent#filterEquals(Intent) Intent.filterEquals}, then you will get
+ * the same PendingIntent for both of them.
+ *
+ * <p>There are two typical ways to deal with this.
+ *
+ * <p>If you truly need multiple distinct PendingIntent objects active at
+ * the same time (such as to use as two notifications that are both shown
+ * at the same time), then you will need to ensure there is something that
+ * is different about them to associate them with different PendingIntents.
+ * This may be any of the Intent attributes considered by
+ * {@link Intent#filterEquals(Intent) Intent.filterEquals}, or different
+ * request code integers supplied to {@link #getActivity}, {@link #getActivities},
+ * {@link #getBroadcast}, or {@link #getService}.
+ *
+ * <p>If you only need one PendingIntent active at a time for any of the
+ * Intents you will use, then you can alternatively use the flags
+ * {@link #FLAG_CANCEL_CURRENT} or {@link #FLAG_UPDATE_CURRENT} to either
+ * cancel or modify whatever current PendingIntent is associated with the
+ * Intent you are supplying.
*/
public final class PendingIntent implements Parcelable {
private final IIntentSender mTarget;
@@ -385,6 +413,13 @@ public final class PendingIntent implements Parcelable {
*/
public static PendingIntent getBroadcast(Context context, int requestCode,
Intent intent, int flags) {
+ return getBroadcastAsUser(context, requestCode, intent, flags,
+ new UserHandle(UserHandle.myUserId()));
+ }
+
+ /** @hide */
+ public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
+ Intent intent, int flags, UserHandle userHandle) {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
@@ -395,7 +430,7 @@ public final class PendingIntent implements Parcelable {
ActivityManager.INTENT_SENDER_BROADCAST, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
- flags, null, UserHandle.myUserId());
+ flags, null, userHandle.getIdentifier());
return target != null ? new PendingIntent(target) : null;
} catch (RemoteException e) {
}
@@ -622,6 +657,20 @@ public final class PendingIntent implements Parcelable {
}
/**
+ * @deprecated Renamed to {@link #getCreatorPackage()}.
+ */
+ @Deprecated
+ public String getTargetPackage() {
+ try {
+ return ActivityManagerNative.getDefault()
+ .getPackageForIntentSender(mTarget);
+ } catch (RemoteException e) {
+ // Should never happen.
+ return null;
+ }
+ }
+
+ /**
* Return the package name of the application that created this
* PendingIntent, that is the identity under which you will actually be
* sending the Intent. The returned string is supplied by the system, so
@@ -630,7 +679,7 @@ public final class PendingIntent implements Parcelable {
* @return The package name of the PendingIntent, or null if there is
* none associated with it.
*/
- public String getTargetPackage() {
+ public String getCreatorPackage() {
try {
return ActivityManagerNative.getDefault()
.getPackageForIntentSender(mTarget);
@@ -649,7 +698,7 @@ public final class PendingIntent implements Parcelable {
* @return The uid of the PendingIntent, or -1 if there is
* none associated with it.
*/
- public int getTargetUid() {
+ public int getCreatorUid() {
try {
return ActivityManagerNative.getDefault()
.getUidForIntentSender(mTarget);
@@ -670,7 +719,7 @@ public final class PendingIntent implements Parcelable {
* @return The user handle of the PendingIntent, or null if there is
* none associated with it.
*/
- public UserHandle getTargetUserHandle() {
+ public UserHandle getCreatorUserHandle() {
try {
int uid = ActivityManagerNative.getDefault()
.getUidForIntentSender(mTarget);
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index 9c83362..cadf5e4 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -162,7 +162,7 @@ public class TaskStackBuilder {
ActivityInfo info = pm.getActivityInfo(sourceActivityName, 0);
String parentActivity = info.parentActivityName;
while (parentActivity != null) {
- final ComponentName target = new ComponentName(mSourceContext, parentActivity);
+ final ComponentName target = new ComponentName(info.packageName, parentActivity);
info = pm.getActivityInfo(target, 0);
parentActivity = info.parentActivityName;
final Intent parent = parentActivity == null && insertAt == 0
@@ -216,11 +216,7 @@ public class TaskStackBuilder {
"No intents added to TaskStackBuilder; cannot startActivities");
}
- Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
- intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_CLEAR_TASK |
- Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- mSourceContext.startActivities(intents, options);
+ mSourceContext.startActivities(getIntents(), options);
}
/**
@@ -260,11 +256,8 @@ public class TaskStackBuilder {
"No intents added to TaskStackBuilder; cannot getPendingIntent");
}
- Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
- intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_CLEAR_TASK |
- Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- return PendingIntent.getActivities(mSourceContext, requestCode, intents, flags, options);
+ return PendingIntent.getActivities(mSourceContext, requestCode, getIntents(),
+ flags, options);
}
/**
@@ -275,6 +268,15 @@ public class TaskStackBuilder {
* @return An array containing the intents added to this builder.
*/
public Intent[] getIntents() {
- return mIntents.toArray(new Intent[mIntents.size()]);
+ Intent[] intents = new Intent[mIntents.size()];
+ if (intents.length == 0) return intents;
+
+ intents[0] = new Intent(mIntents.get(0)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TASK |
+ Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ for (int i = 1; i < intents.length; i++) {
+ intents[i] = new Intent(mIntents.get(i));
+ }
+ return intents;
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4c55bb3..600d02a 100755
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -29,6 +29,7 @@ import android.os.Handler;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Log;
import java.io.IOException;
@@ -131,7 +132,7 @@ public class DevicePolicyManager {
public boolean isAdminActive(ComponentName who) {
if (mService != null) {
try {
- return mService.isAdminActive(who);
+ return mService.isAdminActive(who, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -147,7 +148,7 @@ public class DevicePolicyManager {
public List<ComponentName> getActiveAdmins() {
if (mService != null) {
try {
- return mService.getActiveAdmins();
+ return mService.getActiveAdmins(UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -156,12 +157,14 @@ public class DevicePolicyManager {
}
/**
+ * Used by package administration code to determine if a package can be stopped
+ * or uninstalled.
* @hide
*/
public boolean packageHasActiveAdmins(String packageName) {
if (mService != null) {
try {
- return mService.packageHasActiveAdmins(packageName);
+ return mService.packageHasActiveAdmins(packageName, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -178,7 +181,7 @@ public class DevicePolicyManager {
public void removeActiveAdmin(ComponentName who) {
if (mService != null) {
try {
- mService.removeActiveAdmin(who);
+ mService.removeActiveAdmin(who, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -197,7 +200,7 @@ public class DevicePolicyManager {
public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) {
if (mService != null) {
try {
- return mService.hasGrantedPolicy(admin, usesPolicy);
+ return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -289,7 +292,7 @@ public class DevicePolicyManager {
public void setPasswordQuality(ComponentName admin, int quality) {
if (mService != null) {
try {
- mService.setPasswordQuality(admin, quality);
+ mService.setPasswordQuality(admin, quality, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -303,9 +306,14 @@ public class DevicePolicyManager {
* all admins.
*/
public int getPasswordQuality(ComponentName admin) {
+ return getPasswordQuality(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordQuality(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordQuality(admin);
+ return mService.getPasswordQuality(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -337,7 +345,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumLength(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumLength(admin, length);
+ mService.setPasswordMinimumLength(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -351,9 +359,14 @@ public class DevicePolicyManager {
* all admins.
*/
public int getPasswordMinimumLength(ComponentName admin) {
+ return getPasswordMinimumLength(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumLength(admin);
+ return mService.getPasswordMinimumLength(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -386,7 +399,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumUpperCase(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumUpperCase(admin, length);
+ mService.setPasswordMinimumUpperCase(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -406,9 +419,14 @@ public class DevicePolicyManager {
* password.
*/
public int getPasswordMinimumUpperCase(ComponentName admin) {
+ return getPasswordMinimumUpperCase(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumUpperCase(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumUpperCase(admin);
+ return mService.getPasswordMinimumUpperCase(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -441,7 +459,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumLowerCase(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumLowerCase(admin, length);
+ mService.setPasswordMinimumLowerCase(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -461,9 +479,14 @@ public class DevicePolicyManager {
* password.
*/
public int getPasswordMinimumLowerCase(ComponentName admin) {
+ return getPasswordMinimumLowerCase(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumLowerCase(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumLowerCase(admin);
+ return mService.getPasswordMinimumLowerCase(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -495,7 +518,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumLetters(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumLetters(admin, length);
+ mService.setPasswordMinimumLetters(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -514,9 +537,14 @@ public class DevicePolicyManager {
* @return The minimum number of letters required in the password.
*/
public int getPasswordMinimumLetters(ComponentName admin) {
+ return getPasswordMinimumLetters(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumLetters(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumLetters(admin);
+ return mService.getPasswordMinimumLetters(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -548,7 +576,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumNumeric(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumNumeric(admin, length);
+ mService.setPasswordMinimumNumeric(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -567,9 +595,14 @@ public class DevicePolicyManager {
* @return The minimum number of numerical digits required in the password.
*/
public int getPasswordMinimumNumeric(ComponentName admin) {
+ return getPasswordMinimumNumeric(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumNumeric(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumNumeric(admin);
+ return mService.getPasswordMinimumNumeric(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -601,7 +634,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumSymbols(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumSymbols(admin, length);
+ mService.setPasswordMinimumSymbols(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -620,9 +653,14 @@ public class DevicePolicyManager {
* @return The minimum number of symbols required in the password.
*/
public int getPasswordMinimumSymbols(ComponentName admin) {
+ return getPasswordMinimumSymbols(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumSymbols(admin);
+ return mService.getPasswordMinimumSymbols(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -654,7 +692,7 @@ public class DevicePolicyManager {
public void setPasswordMinimumNonLetter(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordMinimumNonLetter(admin, length);
+ mService.setPasswordMinimumNonLetter(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -673,9 +711,14 @@ public class DevicePolicyManager {
* @return The minimum number of letters required in the password.
*/
public int getPasswordMinimumNonLetter(ComponentName admin) {
+ return getPasswordMinimumNonLetter(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordMinimumNonLetter(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordMinimumNonLetter(admin);
+ return mService.getPasswordMinimumNonLetter(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -708,7 +751,7 @@ public class DevicePolicyManager {
public void setPasswordHistoryLength(ComponentName admin, int length) {
if (mService != null) {
try {
- mService.setPasswordHistoryLength(admin, length);
+ mService.setPasswordHistoryLength(admin, length, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -737,7 +780,7 @@ public class DevicePolicyManager {
public void setPasswordExpirationTimeout(ComponentName admin, long timeout) {
if (mService != null) {
try {
- mService.setPasswordExpirationTimeout(admin, timeout);
+ mService.setPasswordExpirationTimeout(admin, timeout, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -756,7 +799,7 @@ public class DevicePolicyManager {
public long getPasswordExpirationTimeout(ComponentName admin) {
if (mService != null) {
try {
- return mService.getPasswordExpirationTimeout(admin);
+ return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -776,7 +819,7 @@ public class DevicePolicyManager {
public long getPasswordExpiration(ComponentName admin) {
if (mService != null) {
try {
- return mService.getPasswordExpiration(admin);
+ return mService.getPasswordExpiration(admin, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -792,9 +835,14 @@ public class DevicePolicyManager {
* @return The length of the password history
*/
public int getPasswordHistoryLength(ComponentName admin) {
+ return getPasswordHistoryLength(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getPasswordHistoryLength(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordHistoryLength(admin);
+ return mService.getPasswordHistoryLength(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -828,7 +876,7 @@ public class DevicePolicyManager {
public boolean isActivePasswordSufficient() {
if (mService != null) {
try {
- return mService.isActivePasswordSufficient();
+ return mService.isActivePasswordSufficient(UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -847,7 +895,7 @@ public class DevicePolicyManager {
public int getCurrentFailedPasswordAttempts() {
if (mService != null) {
try {
- return mService.getCurrentFailedPasswordAttempts();
+ return mService.getCurrentFailedPasswordAttempts(UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -877,7 +925,7 @@ public class DevicePolicyManager {
public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
if (mService != null) {
try {
- mService.setMaximumFailedPasswordsForWipe(admin, num);
+ mService.setMaximumFailedPasswordsForWipe(admin, num, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -892,9 +940,14 @@ public class DevicePolicyManager {
* all admins.
*/
public int getMaximumFailedPasswordsForWipe(ComponentName admin) {
+ return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getMaximumFailedPasswordsForWipe(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getMaximumFailedPasswordsForWipe(admin);
+ return mService.getMaximumFailedPasswordsForWipe(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -933,7 +986,7 @@ public class DevicePolicyManager {
public boolean resetPassword(String password, int flags) {
if (mService != null) {
try {
- return mService.resetPassword(password, flags);
+ return mService.resetPassword(password, flags, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -957,7 +1010,7 @@ public class DevicePolicyManager {
public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
if (mService != null) {
try {
- mService.setMaximumTimeToLock(admin, timeMs);
+ mService.setMaximumTimeToLock(admin, timeMs, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -971,9 +1024,14 @@ public class DevicePolicyManager {
* all admins.
*/
public long getMaximumTimeToLock(ComponentName admin) {
+ return getMaximumTimeToLock(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public long getMaximumTimeToLock(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getMaximumTimeToLock(admin);
+ return mService.getMaximumTimeToLock(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1021,7 +1079,7 @@ public class DevicePolicyManager {
public void wipeData(int flags) {
if (mService != null) {
try {
- mService.wipeData(flags);
+ mService.wipeData(flags, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1090,7 +1148,7 @@ public class DevicePolicyManager {
}
android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec);
}
- return mService.setGlobalProxy(admin, hostSpec, exclSpec);
+ return mService.setGlobalProxy(admin, hostSpec, exclSpec, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1107,7 +1165,7 @@ public class DevicePolicyManager {
public ComponentName getGlobalProxyAdmin() {
if (mService != null) {
try {
- return mService.getGlobalProxyAdmin();
+ return mService.getGlobalProxyAdmin(UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1199,7 +1257,7 @@ public class DevicePolicyManager {
public int setStorageEncryption(ComponentName admin, boolean encrypt) {
if (mService != null) {
try {
- return mService.setStorageEncryption(admin, encrypt);
+ return mService.setStorageEncryption(admin, encrypt, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1219,7 +1277,7 @@ public class DevicePolicyManager {
public boolean getStorageEncryption(ComponentName admin) {
if (mService != null) {
try {
- return mService.getStorageEncryption(admin);
+ return mService.getStorageEncryption(admin, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1244,9 +1302,14 @@ public class DevicePolicyManager {
* {@link #ENCRYPTION_STATUS_ACTIVATING}, or{@link #ENCRYPTION_STATUS_ACTIVE}.
*/
public int getStorageEncryptionStatus() {
+ return getStorageEncryptionStatus(UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getStorageEncryptionStatus(int userHandle) {
if (mService != null) {
try {
- return mService.getStorageEncryptionStatus();
+ return mService.getStorageEncryptionStatus(userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1269,7 +1332,7 @@ public class DevicePolicyManager {
public void setCameraDisabled(ComponentName admin, boolean disabled) {
if (mService != null) {
try {
- mService.setCameraDisabled(admin, disabled);
+ mService.setCameraDisabled(admin, disabled, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1283,9 +1346,14 @@ public class DevicePolicyManager {
* have disabled the camera
*/
public boolean getCameraDisabled(ComponentName admin) {
+ return getCameraDisabled(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public boolean getCameraDisabled(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getCameraDisabled(admin);
+ return mService.getCameraDisabled(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1309,7 +1377,7 @@ public class DevicePolicyManager {
public void setKeyguardWidgetsDisabled(ComponentName admin, int which) {
if (mService != null) {
try {
- mService.setKeyguardWidgetsDisabled(admin, which);
+ mService.setKeyguardWidgetsDisabled(admin, which, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1323,9 +1391,14 @@ public class DevicePolicyManager {
* have disabled widgets in keyguard.
*/
public int getKeyguardWidgetsDisabled(ComponentName admin) {
+ return getKeyguardWidgetsDisabled(admin, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public int getKeyguardWidgetsDisabled(ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getKeyguardWidgetsDisabled(admin);
+ return mService.getKeyguardWidgetsDisabled(admin, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1339,7 +1412,7 @@ public class DevicePolicyManager {
public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
if (mService != null) {
try {
- mService.setActiveAdmin(policyReceiver, refreshing);
+ mService.setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1380,7 +1453,7 @@ public class DevicePolicyManager {
public void getRemoveWarning(ComponentName admin, RemoteCallback result) {
if (mService != null) {
try {
- mService.getRemoveWarning(admin, result);
+ mService.getRemoveWarning(admin, result, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1391,11 +1464,11 @@ public class DevicePolicyManager {
* @hide
*/
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
- int lowercase, int numbers, int symbols, int nonletter) {
+ int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
if (mService != null) {
try {
mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
- numbers, symbols, nonletter);
+ numbers, symbols, nonletter, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1405,10 +1478,10 @@ public class DevicePolicyManager {
/**
* @hide
*/
- public void reportFailedPasswordAttempt() {
+ public void reportFailedPasswordAttempt(int userHandle) {
if (mService != null) {
try {
- mService.reportFailedPasswordAttempt();
+ mService.reportFailedPasswordAttempt(userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1418,14 +1491,13 @@ public class DevicePolicyManager {
/**
* @hide
*/
- public void reportSuccessfulPasswordAttempt() {
+ public void reportSuccessfulPasswordAttempt(int userHandle) {
if (mService != null) {
try {
- mService.reportSuccessfulPasswordAttempt();
+ mService.reportSuccessfulPasswordAttempt(userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
}
}
-
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0b7ec12..bdfb177 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -25,76 +25,76 @@ import android.os.RemoteCallback;
* {@hide}
*/
interface IDevicePolicyManager {
- void setPasswordQuality(in ComponentName who, int quality);
- int getPasswordQuality(in ComponentName who);
+ void setPasswordQuality(in ComponentName who, int quality, int userHandle);
+ int getPasswordQuality(in ComponentName who, int userHandle);
- void setPasswordMinimumLength(in ComponentName who, int length);
- int getPasswordMinimumLength(in ComponentName who);
+ void setPasswordMinimumLength(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumLength(in ComponentName who, int userHandle);
- void setPasswordMinimumUpperCase(in ComponentName who, int length);
- int getPasswordMinimumUpperCase(in ComponentName who);
+ void setPasswordMinimumUpperCase(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumUpperCase(in ComponentName who, int userHandle);
- void setPasswordMinimumLowerCase(in ComponentName who, int length);
- int getPasswordMinimumLowerCase(in ComponentName who);
+ void setPasswordMinimumLowerCase(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumLowerCase(in ComponentName who, int userHandle);
- void setPasswordMinimumLetters(in ComponentName who, int length);
- int getPasswordMinimumLetters(in ComponentName who);
+ void setPasswordMinimumLetters(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumLetters(in ComponentName who, int userHandle);
- void setPasswordMinimumNumeric(in ComponentName who, int length);
- int getPasswordMinimumNumeric(in ComponentName who);
+ void setPasswordMinimumNumeric(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumNumeric(in ComponentName who, int userHandle);
- void setPasswordMinimumSymbols(in ComponentName who, int length);
- int getPasswordMinimumSymbols(in ComponentName who);
+ void setPasswordMinimumSymbols(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumSymbols(in ComponentName who, int userHandle);
- void setPasswordMinimumNonLetter(in ComponentName who, int length);
- int getPasswordMinimumNonLetter(in ComponentName who);
+ void setPasswordMinimumNonLetter(in ComponentName who, int length, int userHandle);
+ int getPasswordMinimumNonLetter(in ComponentName who, int userHandle);
- void setPasswordHistoryLength(in ComponentName who, int length);
- int getPasswordHistoryLength(in ComponentName who);
+ void setPasswordHistoryLength(in ComponentName who, int length, int userHandle);
+ int getPasswordHistoryLength(in ComponentName who, int userHandle);
- void setPasswordExpirationTimeout(in ComponentName who, long expiration);
- long getPasswordExpirationTimeout(in ComponentName who);
+ void setPasswordExpirationTimeout(in ComponentName who, long expiration, int userHandle);
+ long getPasswordExpirationTimeout(in ComponentName who, int userHandle);
- long getPasswordExpiration(in ComponentName who);
+ long getPasswordExpiration(in ComponentName who, int userHandle);
- boolean isActivePasswordSufficient();
- int getCurrentFailedPasswordAttempts();
+ boolean isActivePasswordSufficient(int userHandle);
+ int getCurrentFailedPasswordAttempts(int userHandle);
- void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
- int getMaximumFailedPasswordsForWipe(in ComponentName admin);
+ void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, int userHandle);
+ int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle);
- boolean resetPassword(String password, int flags);
+ boolean resetPassword(String password, int flags, int userHandle);
- void setMaximumTimeToLock(in ComponentName who, long timeMs);
- long getMaximumTimeToLock(in ComponentName who);
+ void setMaximumTimeToLock(in ComponentName who, long timeMs, int userHandle);
+ long getMaximumTimeToLock(in ComponentName who, int userHandle);
void lockNow();
- void wipeData(int flags);
+ void wipeData(int flags, int userHandle);
- ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
- ComponentName getGlobalProxyAdmin();
+ ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList, int userHandle);
+ ComponentName getGlobalProxyAdmin(int userHandle);
- int setStorageEncryption(in ComponentName who, boolean encrypt);
- boolean getStorageEncryption(in ComponentName who);
- int getStorageEncryptionStatus();
+ int setStorageEncryption(in ComponentName who, boolean encrypt, int userHandle);
+ boolean getStorageEncryption(in ComponentName who, int userHandle);
+ int getStorageEncryptionStatus(int userHandle);
- void setCameraDisabled(in ComponentName who, boolean disabled);
- boolean getCameraDisabled(in ComponentName who);
+ void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle);
+ boolean getCameraDisabled(in ComponentName who, int userHandle);
- void setKeyguardWidgetsDisabled(in ComponentName who, int which);
- int getKeyguardWidgetsDisabled(in ComponentName who);
+ void setKeyguardWidgetsDisabled(in ComponentName who, int which, int userHandle);
+ int getKeyguardWidgetsDisabled(in ComponentName who, int userHandle);
- void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing);
- boolean isAdminActive(in ComponentName policyReceiver);
- List<ComponentName> getActiveAdmins();
- boolean packageHasActiveAdmins(String packageName);
- void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
- void removeActiveAdmin(in ComponentName policyReceiver);
- boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy);
+ void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle);
+ boolean isAdminActive(in ComponentName policyReceiver, int userHandle);
+ List<ComponentName> getActiveAdmins(int userHandle);
+ boolean packageHasActiveAdmins(String packageName, int userHandle);
+ void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result, int userHandle);
+ void removeActiveAdmin(in ComponentName policyReceiver, int userHandle);
+ boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle);
void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase,
- int numbers, int symbols, int nonletter);
- void reportFailedPasswordAttempt();
- void reportSuccessfulPasswordAttempt();
+ int numbers, int symbols, int nonletter, int userHandle);
+ void reportFailedPasswordAttempt(int userHandle);
+ void reportSuccessfulPasswordAttempt(int userHandle);
}
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 51a81c5..185fb5a 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -19,6 +19,7 @@ package android.appwidget;
import java.util.ArrayList;
import java.util.HashMap;
+import android.app.ActivityThread;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -117,7 +118,7 @@ public class AppWidgetHost {
private OnClickHandler mOnClickHandler;
public AppWidgetHost(Context context, int hostId) {
- this(context, hostId, null, Looper.getMainLooper());
+ this(context, hostId, null, context.getMainLooper());
}
/**
@@ -201,12 +202,15 @@ public class AppWidgetHost {
* @return a appWidgetId
* @hide
*/
- public static int allocateAppWidgetIdForHost(String packageName, int hostId) {
+ public static int allocateAppWidgetIdForSystem(int hostId) {
checkCallerIsSystem();
try {
if (sService == null) {
bindService();
}
+ Context systemContext =
+ (Context) ActivityThread.currentActivityThread().getSystemContext();
+ String packageName = systemContext.getPackageName();
return sService.allocateAppWidgetId(packageName, hostId);
} catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
@@ -240,7 +244,7 @@ public class AppWidgetHost {
* Stop listening to changes for this AppWidget.
* @hide
*/
- public static void deleteAppWidgetIdForHost(int appWidgetId) {
+ public static void deleteAppWidgetIdForSystem(int appWidgetId) {
checkCallerIsSystem();
try {
if (sService == null) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index ece8841..cd1e882 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1219,9 +1219,16 @@ public abstract class ContentResolver {
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer)
{
+ registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
+ }
+
+ /** @hide - designated user version */
+ public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer, int userHandle)
+ {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
- observer.getContentObserver());
+ observer.getContentObserver(), userHandle);
} catch (RemoteException e) {
}
}
@@ -1276,10 +1283,21 @@ public abstract class ContentResolver {
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
*/
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
+ }
+
+ /**
+ * Notify registered observers within the designated user(s) that a row was updated.
+ *
+ * @hide
+ */
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
+ int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
- observer != null && observer.deliverSelfNotifications(), syncToNetwork);
+ observer != null && observer.deliverSelfNotifications(), syncToNetwork,
+ userHandle);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 472fe94..5986dcd 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -17,6 +17,7 @@
package android.content;
import android.accounts.Account;
+import android.app.ActivityManager;
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
@@ -33,6 +34,7 @@ import android.Manifest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -138,19 +140,53 @@ public final class ContentService extends IContentService.Stub {
getSyncManager();
}
- public void registerContentObserver(Uri uri, boolean notifyForDescendents,
- IContentObserver observer) {
+ /**
+ * Register a content observer tied to a specific user's view of the provider.
+ * @param userHandle the user whose view of the provider is to be observed. May be
+ * the calling user without requiring any permission, otherwise the caller needs to
+ * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and
+ * USER_CURRENT are properly handled; all other pseudousers are forbidden.
+ */
+ @Override
+ public void registerContentObserver(Uri uri, boolean notifyForDescendants,
+ IContentObserver observer, int userHandle) {
if (observer == null || uri == null) {
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
+
+ // STOPSHIP: disable the multi-user permission checks until a solid fix for the
+ // content provider / observer case is in place.
+ /*
+ final int callingUser = UserHandle.getCallingUserId();
+ if (callingUser != userHandle) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "no permission to observe other users' provider view");
+ }
+ */
+
+ if (userHandle < 0) {
+ if (userHandle == UserHandle.USER_CURRENT) {
+ userHandle = ActivityManager.getCurrentUser();
+ } else if (userHandle != UserHandle.USER_ALL) {
+ throw new InvalidParameterException("Bad user handle for registerContentObserver: "
+ + userHandle);
+ }
+ }
+
synchronized (mRootNode) {
- mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode,
- Binder.getCallingUid(), Binder.getCallingPid());
+ mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
+ Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
- " with notifyForDescendents " + notifyForDescendents);
+ " with notifyForDescendants " + notifyForDescendants);
}
}
+ public void registerContentObserver(Uri uri, boolean notifyForDescendants,
+ IContentObserver observer) {
+ registerContentObserver(uri, notifyForDescendants, observer,
+ UserHandle.getCallingUserId());
+ }
+
public void unregisterContentObserver(IContentObserver observer) {
if (observer == null) {
throw new IllegalArgumentException("You must pass a valid observer");
@@ -161,14 +197,39 @@ public final class ContentService extends IContentService.Stub {
}
}
+ /**
+ * Notify observers of a particular user's view of the provider.
+ * @param userHandle the user whose view of the provider is to be notified. May be
+ * the calling user without requiring any permission, otherwise the caller needs to
+ * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and
+ * USER_CURRENT are properly interpreted; no other pseudousers are allowed.
+ */
+ @Override
public void notifyChange(Uri uri, IContentObserver observer,
- boolean observerWantsSelfNotifications, boolean syncToNetwork) {
+ boolean observerWantsSelfNotifications, boolean syncToNetwork,
+ int userHandle) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Notifying update of " + uri + " from observer " + observer
- + ", syncToNetwork " + syncToNetwork);
+ Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle
+ + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
+ }
+
+ // Notify for any user other than the caller's own requires permission.
+ final int callingUserHandle = UserHandle.getCallingUserId();
+ if (userHandle != callingUserHandle) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "no permission to notify other users");
+ }
+
+ // We passed the permission check; resolve pseudouser targets as appropriate
+ if (userHandle < 0) {
+ if (userHandle == UserHandle.USER_CURRENT) {
+ userHandle = ActivityManager.getCurrentUser();
+ } else if (userHandle != UserHandle.USER_ALL) {
+ throw new InvalidParameterException("Bad user handle for notifyChange: "
+ + userHandle);
+ }
}
- int userId = UserHandle.getCallingUserId();
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
@@ -176,7 +237,7 @@ public final class ContentService extends IContentService.Stub {
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
synchronized (mRootNode) {
mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
- calls);
+ userHandle, calls);
}
final int numCalls = calls.size();
for (int i=0; i<numCalls; i++) {
@@ -207,7 +268,7 @@ public final class ContentService extends IContentService.Stub {
if (syncToNetwork) {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.scheduleLocalSync(null /* all accounts */, userId,
+ syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle,
uri.getAuthority());
}
}
@@ -216,6 +277,12 @@ public final class ContentService extends IContentService.Stub {
}
}
+ public void notifyChange(Uri uri, IContentObserver observer,
+ boolean observerWantsSelfNotifications, boolean syncToNetwork) {
+ notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
+ UserHandle.getCallingUserId());
+ }
+
/**
* Hide this class since it is not part of api,
* but current unittest framework requires it to be public
@@ -543,16 +610,18 @@ public final class ContentService extends IContentService.Stub {
public final IContentObserver observer;
public final int uid;
public final int pid;
- public final boolean notifyForDescendents;
+ public final boolean notifyForDescendants;
+ private final int userHandle;
private final Object observersLock;
public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
- int _uid, int _pid) {
+ int _uid, int _pid, int _userHandle) {
this.observersLock = observersLock;
observer = o;
uid = _uid;
pid = _pid;
- notifyForDescendents = n;
+ userHandle = _userHandle;
+ notifyForDescendants = n;
try {
observer.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -571,7 +640,8 @@ public final class ContentService extends IContentService.Stub {
pidCounts.put(pid, pidCounts.get(pid)+1);
pw.print(prefix); pw.print(name); pw.print(": pid=");
pw.print(pid); pw.print(" uid=");
- pw.print(uid); pw.print(" target=");
+ pw.print(uid); pw.print(" user=");
+ pw.print(userHandle); pw.print(" target=");
pw.println(Integer.toHexString(System.identityHashCode(
observer != null ? observer.asBinder() : null)));
}
@@ -639,17 +709,21 @@ public final class ContentService extends IContentService.Stub {
return uri.getPathSegments().size() + 1;
}
+ // Invariant: userHandle is either a hard user number or is USER_ALL
public void addObserverLocked(Uri uri, IContentObserver observer,
- boolean notifyForDescendents, Object observersLock, int uid, int pid) {
- addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid);
+ boolean notifyForDescendants, Object observersLock,
+ int uid, int pid, int userHandle) {
+ addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
+ uid, pid, userHandle);
}
private void addObserverLocked(Uri uri, int index, IContentObserver observer,
- boolean notifyForDescendents, Object observersLock, int uid, int pid) {
+ boolean notifyForDescendants, Object observersLock,
+ int uid, int pid, int userHandle) {
// If this is the leaf node add the observer
if (index == countUriSegments(uri)) {
- mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock,
- uid, pid));
+ mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
+ uid, pid, userHandle));
return;
}
@@ -662,8 +736,8 @@ public final class ContentService extends IContentService.Stub {
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (node.mName.equals(segment)) {
- node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
- observersLock, uid, pid);
+ node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
+ observersLock, uid, pid, userHandle);
return;
}
}
@@ -671,8 +745,8 @@ public final class ContentService extends IContentService.Stub {
// No child found, create one
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
- node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
- observersLock, uid, pid);
+ node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
+ observersLock, uid, pid, userHandle);
}
public boolean removeObserverLocked(IContentObserver observer) {
@@ -705,37 +779,49 @@ public final class ContentService extends IContentService.Stub {
}
private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
- boolean observerWantsSelfNotifications, ArrayList<ObserverCall> calls) {
+ boolean observerWantsSelfNotifications, int targetUserHandle,
+ ArrayList<ObserverCall> calls) {
int N = mObservers.size();
IBinder observerBinder = observer == null ? null : observer.asBinder();
for (int i = 0; i < N; i++) {
ObserverEntry entry = mObservers.get(i);
- // Don't notify the observer if it sent the notification and isn't interesed
+ // Don't notify the observer if it sent the notification and isn't interested
// in self notifications
boolean selfChange = (entry.observer.asBinder() == observerBinder);
if (selfChange && !observerWantsSelfNotifications) {
continue;
}
- // Make sure the observer is interested in the notification
- if (leaf || (!leaf && entry.notifyForDescendents)) {
- calls.add(new ObserverCall(this, entry.observer, selfChange));
+ // Does this observer match the target user?
+ if (targetUserHandle == UserHandle.USER_ALL
+ || entry.userHandle == UserHandle.USER_ALL
+ || targetUserHandle == entry.userHandle) {
+ // Make sure the observer is interested in the notification
+ if (leaf || (!leaf && entry.notifyForDescendants)) {
+ calls.add(new ObserverCall(this, entry.observer, selfChange));
+ }
}
}
}
+ /**
+ * targetUserHandle is either a hard user handle or is USER_ALL
+ */
public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
- boolean observerWantsSelfNotifications, ArrayList<ObserverCall> calls) {
+ boolean observerWantsSelfNotifications, int targetUserHandle,
+ ArrayList<ObserverCall> calls) {
String segment = null;
int segmentCount = countUriSegments(uri);
if (index >= segmentCount) {
// This is the leaf node, notify all observers
- collectMyObserversLocked(true, observer, observerWantsSelfNotifications, calls);
+ collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
+ targetUserHandle, calls);
} else if (index < segmentCount){
segment = getUriSegment(uri, index);
- // Notify any observers at this level who are interested in descendents
- collectMyObserversLocked(false, observer, observerWantsSelfNotifications, calls);
+ // Notify any observers at this level who are interested in descendants
+ collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
+ targetUserHandle, calls);
}
int N = mChildren.size();
@@ -744,7 +830,7 @@ public final class ContentService extends IContentService.Stub {
if (segment == null || node.mName.equals(segment)) {
// We found the child,
node.collectObserversLocked(uri, index + 1,
- observer, observerWantsSelfNotifications, calls);
+ observer, observerWantsSelfNotifications, targetUserHandle, calls);
if (segment != null) {
break;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7438ba8..161670f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -856,8 +856,10 @@ public abstract class Context {
public abstract void startActivity(Intent intent);
/**
- * Same as {@link #startActivity(Intent)}, but for a specific user. It requires holding
- * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+ * Version of {@link #startActivity(Intent)} that allows you to specify the
+ * user the activity will be started for. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS_FULL permission.
* @param intent The description of the activity to start.
* @param user The UserHandle of the user to start this activity for.
* @throws ActivityNotFoundException
@@ -895,8 +897,10 @@ public abstract class Context {
public abstract void startActivity(Intent intent, Bundle options);
/**
- * Same as {@link #startActivity(Intent, Bundle)}, but for a specific user. It requires holding
- * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+ * Version of {@link #startActivity(Intent, Bundle)} that allows you to specify the
+ * user the activity will be started for. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS_FULL permission.
* @param intent The description of the activity to start.
* @param options Additional options for how the Activity should be started.
* May be null if there are no options. See {@link android.app.ActivityOptions}
@@ -1118,10 +1122,10 @@ public abstract class Context {
Bundle initialExtras);
/**
- * Same as {@link #sendBroadcast(Intent)}, but for a specific user. This broadcast
- * can only be sent to receivers that are part of the calling application. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * permission.
+ * Version of {@link #sendBroadcast(Intent)} that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
* @param intent The intent to broadcast
* @param user UserHandle to send the intent to.
* @see #sendBroadcast(Intent)
@@ -1129,10 +1133,10 @@ public abstract class Context {
public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);
/**
- * Same as {@link #sendBroadcast(Intent, String)}, but for a specific user. This broadcast
- * can only be sent to receivers that are part of the calling application. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * permission.
+ * Version of {@link #sendBroadcast(Intent, String)} that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
*
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
@@ -1147,12 +1151,12 @@ public abstract class Context {
String receiverPermission);
/**
- * Same as
- * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)},
- * but for a specific user. This broadcast
- * can only be sent to receivers that are part of the calling application. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * permission.
+ * Version of
+ * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)}
+ * that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
@@ -1261,11 +1265,10 @@ public abstract class Context {
public abstract void removeStickyBroadcast(Intent intent);
/**
- * Same as {@link #sendStickyBroadcast(Intent)},
- * but for a specific user. This broadcast
- * can only be sent to receivers that are part of the calling application. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * permission.
+ * Version of {@link #sendStickyBroadcast(Intent)} that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
*
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast, and the Intent will be held to
@@ -1277,12 +1280,12 @@ public abstract class Context {
public abstract void sendStickyBroadcastAsUser(Intent intent, UserHandle user);
/**
- * Same as
- * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
- * but for a specific user. This broadcast
- * can only be sent to receivers that are part of the calling application. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * permission.
+ * Version of
+ * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)}
+ * that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
@@ -1309,12 +1312,10 @@ public abstract class Context {
Bundle initialExtras);
/**
- * Same as
- * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
- * but for a specific user. This broadcast
- * can only be sent to receivers that are part of the calling application. It
- * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * permission.
+ * Version of {@link #removeStickyBroadcast(Intent)} that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
*
* <p>You must hold the {@link android.Manifest.permission#BROADCAST_STICKY}
* permission in order to use this API. If you do not hold that
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 86a9392..f956bcf 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -30,12 +30,28 @@ import android.database.IContentObserver;
* @hide
*/
interface IContentService {
- void registerContentObserver(in Uri uri, boolean notifyForDescendentsn,
- IContentObserver observer);
void unregisterContentObserver(IContentObserver observer);
+ /**
+ * Register a content observer tied to a specific user's view of the provider.
+ * @param userHandle the user whose view of the provider is to be observed. May be
+ * the calling user without requiring any permission, otherwise the caller needs to
+ * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and
+ * USER_CURRENT are properly handled.
+ */
+ void registerContentObserver(in Uri uri, boolean notifyForDescendants,
+ IContentObserver observer, int userHandle);
+
+ /**
+ * Notify observers of a particular user's view of the provider.
+ * @param userHandle the user whose view of the provider is to be notified. May be
+ * the calling user without requiring any permission, otherwise the caller needs to
+ * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL
+ * USER_CURRENT are properly interpreted.
+ */
void notifyChange(in Uri uri, IContentObserver observer,
- boolean observerWantsSelfNotifications, boolean syncToNetwork);
+ boolean observerWantsSelfNotifications, boolean syncToNetwork,
+ int userHandle);
void requestSync(in Account account, String authority, in Bundle extras);
void cancelSync(in Account account, String authority);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d3b8648..383739b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1254,7 +1254,9 @@ public class Intent implements Parcelable, Cloneable {
* Activity Action: Launch application installer.
* <p>
* Input: The data must be a content: or file: URI at which the application
- * can be retrieved. You can optionally supply
+ * can be retrieved. As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1},
+ * you can also use "package:<package-name>" to install an application for the
+ * current user that is already installed for another user. You can optionally supply
* {@link #EXTRA_INSTALLER_PACKAGE_NAME}, {@link #EXTRA_NOT_UNKNOWN_SOURCE},
* {@link #EXTRA_ALLOW_REPLACE}, and {@link #EXTRA_RETURN_RESULT}.
* <p>
@@ -2376,6 +2378,16 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_USER_SWITCHED =
"android.intent.action.USER_SWITCHED";
+ /**
+ * Broadcast sent to the system when a user's information changes. Carries an extra
+ * {@link #EXTRA_USER_HANDLE} to indicate which user's information changed.
+ * This is only sent to registered receivers, not manifest receivers. It is sent to the user
+ * whose information has changed.
+ * @hide
+ */
+ public static final String ACTION_USER_INFO_CHANGED =
+ "android.intent.action.USER_INFO_CHANGED";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 6c3cf99..166495b 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -205,6 +205,20 @@ public class IntentSender implements Parcelable {
}
/**
+ * @deprecated Renamed to {@link #getCreatorPackage()}.
+ */
+ @Deprecated
+ public String getTargetPackage() {
+ try {
+ return ActivityManagerNative.getDefault()
+ .getPackageForIntentSender(mTarget);
+ } catch (RemoteException e) {
+ // Should never happen.
+ return null;
+ }
+ }
+
+ /**
* Return the package name of the application that created this
* IntentSender, that is the identity under which you will actually be
* sending the Intent. The returned string is supplied by the system, so
@@ -213,7 +227,7 @@ public class IntentSender implements Parcelable {
* @return The package name of the PendingIntent, or null if there is
* none associated with it.
*/
- public String getTargetPackage() {
+ public String getCreatorPackage() {
try {
return ActivityManagerNative.getDefault()
.getPackageForIntentSender(mTarget);
@@ -232,7 +246,7 @@ public class IntentSender implements Parcelable {
* @return The uid of the PendingIntent, or -1 if there is
* none associated with it.
*/
- public int getTargetUid() {
+ public int getCreatorUid() {
try {
return ActivityManagerNative.getDefault()
.getUidForIntentSender(mTarget);
@@ -253,7 +267,7 @@ public class IntentSender implements Parcelable {
* @return The user handle of the PendingIntent, or null if there is
* none associated with it.
*/
- public UserHandle getTargetUserHandle() {
+ public UserHandle getCreatorUserHandle() {
try {
int uid = ActivityManagerNative.getDefault()
.getUidForIntentSender(mTarget);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4784d7f..fd488ae 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2434,8 +2434,7 @@ public abstract class PackageManager {
* @param verificationCode either {@link PackageManager#VERIFICATION_ALLOW}
* or {@link PackageManager#VERIFICATION_REJECT}.
* @throws SecurityException if the caller does not have the
- * {@link android.Manifest.permission#PACKAGE_VERIFICATION_AGENT}
- * permission.
+ * PACKAGE_VERIFICATION_AGENT permission.
*/
public abstract void verifyPendingInstall(int id, int verificationCode);
@@ -2469,8 +2468,7 @@ public abstract class PackageManager {
* bounds value; namely, 0 or
* {@link PackageManager#MAXIMUM_VERIFICATION_TIMEOUT}.
* @throws SecurityException if the caller does not have the
- * {@link android.Manifest.permission#PACKAGE_VERIFICATION_AGENT}
- * permission.
+ * PACKAGE_VERIFICATION_AGENT permission.
*/
public abstract void extendVerificationTimeout(int id,
int verificationCodeAtTimeout, long millisecondsToDelay);
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 1a71bfb..3579977 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -22,6 +22,7 @@ import java.util.HashSet;
/**
* Per-user state information about a package.
+ * @hide
*/
public class PackageUserState {
public boolean stopped;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 7164713..51b8d25 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -19,7 +19,7 @@ package android.content.res;
import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.LocaleUtil;
+import android.text.TextUtils;
import android.view.View;
import java.util.Locale;
@@ -1169,7 +1169,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public void setLayoutDirection(Locale locale) {
// There is a "1" difference between the configuration values for
// layout direction and View constants for layout direction, just add "1".
- final int layoutDirection = 1 + LocaleUtil.getLayoutDirectionFromLocale(locale);
+ final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
(layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index b316f23..492e5e9 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1554,6 +1554,8 @@ public class Resources {
public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
CompatibilityInfo compat) {
if (mSystem != null) {
+ // TODO: Remove once b/7094175 is fixed
+ Slog.v(TAG, "updateSystemConfiguration: b/7094175 config=" + config);
mSystem.updateConfiguration(config, metrics, compat);
//Log.i(TAG, "Updated system resources " + mSystem
// + ": " + mSystem.getConfiguration());
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 4347e75..58a0f13 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -160,6 +160,10 @@ public final class DisplayManager {
/**
* Connects to a Wifi display.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+ * <p>
+ * Automatically remembers the display after a successful connection, if not
+ * already remembered.
+ * </p>
*
* @param deviceAddress The MAC address of the device to which we should connect.
* @hide
@@ -178,6 +182,36 @@ public final class DisplayManager {
}
/**
+ * Renames a Wifi display.
+ * <p>
+ * The display must already be remembered for this call to succeed. In other words,
+ * we must already have successfully connected to the display at least once and then
+ * not forgotten it.
+ * </p>
+ *
+ * @param deviceAddress The MAC address of the device to rename.
+ * @param alias The alias name by which to remember the device, or null
+ * or empty if no alias should be used.
+ * @hide
+ */
+ public void renameWifiDisplay(String deviceAddress, String alias) {
+ mGlobal.renameWifiDisplay(deviceAddress, alias);
+ }
+
+ /**
+ * Forgets a previously remembered Wifi display.
+ * <p>
+ * Automatically disconnects from the display if currently connected to it.
+ * </p>
+ *
+ * @param deviceAddress The MAC address of the device to forget.
+ * @hide
+ */
+ public void forgetWifiDisplay(String deviceAddress) {
+ mGlobal.forgetWifiDisplay(deviceAddress);
+ }
+
+ /**
* Gets the current Wifi display status.
* Watch for changes in the status by registering a broadcast receiver for
* {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 14b5440..a858681 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -281,6 +281,31 @@ public final class DisplayManagerGlobal {
}
}
+ public void renameWifiDisplay(String deviceAddress, String alias) {
+ if (deviceAddress == null) {
+ throw new IllegalArgumentException("deviceAddress must not be null");
+ }
+
+ try {
+ mDm.renameWifiDisplay(deviceAddress, alias);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
+ + " with alias " + alias + ".", ex);
+ }
+ }
+
+ public void forgetWifiDisplay(String deviceAddress) {
+ if (deviceAddress == null) {
+ throw new IllegalArgumentException("deviceAddress must not be null");
+ }
+
+ try {
+ mDm.forgetWifiDisplay(deviceAddress);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to forget Wifi display.", ex);
+ }
+ }
+
public WifiDisplayStatus getWifiDisplayStatus() {
try {
return mDm.getWifiDisplayStatus();
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 36a9a7f..4b6fb53 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -38,5 +38,11 @@ interface IDisplayManager {
void disconnectWifiDisplay();
// Requires CONFIGURE_WIFI_DISPLAY permission.
+ void renameWifiDisplay(String address, String alias);
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void forgetWifiDisplay(String address);
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
WifiDisplayStatus getWifiDisplayStatus();
}
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
index e51e97e..0138b1c 100644
--- a/core/java/android/hardware/display/WifiDisplay.java
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -19,6 +19,8 @@ package android.hardware.display;
import android.os.Parcel;
import android.os.Parcelable;
+import libcore.util.Objects;
+
/**
* Describes the properties of a Wifi display.
* <p>
@@ -30,6 +32,7 @@ import android.os.Parcelable;
public final class WifiDisplay implements Parcelable {
private final String mDeviceAddress;
private final String mDeviceName;
+ private final String mDeviceAlias;
public static final WifiDisplay[] EMPTY_ARRAY = new WifiDisplay[0];
@@ -37,7 +40,8 @@ public final class WifiDisplay implements Parcelable {
public WifiDisplay createFromParcel(Parcel in) {
String deviceAddress = in.readString();
String deviceName = in.readString();
- return new WifiDisplay(deviceAddress, deviceName);
+ String deviceAlias = in.readString();
+ return new WifiDisplay(deviceAddress, deviceName, deviceAlias);
}
public WifiDisplay[] newArray(int size) {
@@ -45,7 +49,7 @@ public final class WifiDisplay implements Parcelable {
}
};
- public WifiDisplay(String deviceAddress, String deviceName) {
+ public WifiDisplay(String deviceAddress, String deviceName, String deviceAlias) {
if (deviceAddress == null) {
throw new IllegalArgumentException("deviceAddress must not be null");
}
@@ -55,6 +59,7 @@ public final class WifiDisplay implements Parcelable {
mDeviceAddress = deviceAddress;
mDeviceName = deviceName;
+ mDeviceAlias = deviceAlias;
}
/**
@@ -71,6 +76,25 @@ public final class WifiDisplay implements Parcelable {
return mDeviceName;
}
+ /**
+ * Gets the user-specified alias of the Wifi display device, or null if none.
+ * <p>
+ * The alias should be used in the UI whenever available. It is the value
+ * provided by the user when renaming the device.
+ * </p>
+ */
+ public String getDeviceAlias() {
+ return mDeviceAlias;
+ }
+
+ /**
+ * Gets the name to show in the UI.
+ * Uses the device alias if available, otherwise uses the device name.
+ */
+ public String getFriendlyDisplayName() {
+ return mDeviceAlias != null ? mDeviceAlias : mDeviceName;
+ }
+
@Override
public boolean equals(Object o) {
return o instanceof WifiDisplay && equals((WifiDisplay)o);
@@ -79,7 +103,8 @@ public final class WifiDisplay implements Parcelable {
public boolean equals(WifiDisplay other) {
return other != null
&& mDeviceAddress.equals(other.mDeviceAddress)
- && mDeviceName.equals(other.mDeviceName);
+ && mDeviceName.equals(other.mDeviceName)
+ && Objects.equal(mDeviceAlias, other.mDeviceAlias);
}
@Override
@@ -92,6 +117,7 @@ public final class WifiDisplay implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mDeviceAddress);
dest.writeString(mDeviceName);
+ dest.writeString(mDeviceAlias);
}
@Override
@@ -102,6 +128,10 @@ public final class WifiDisplay implements Parcelable {
// For debugging purposes only.
@Override
public String toString() {
- return mDeviceName + " (" + mDeviceAddress + ")";
+ String result = mDeviceName + " (" + mDeviceAddress + ")";
+ if (mDeviceAlias != null) {
+ result += ", alias " + mDeviceAlias;
+ }
+ return result;
}
}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
index d5fe45d..f7e72c4 100644
--- a/core/java/android/hardware/display/WifiDisplayStatus.java
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -23,7 +23,7 @@ import java.util.Arrays;
/**
* Describes the current global state of Wifi display connectivity, including the
- * currently connected display and all known displays.
+ * currently connected display and all available or remembered displays.
* <p>
* This object is immutable.
* </p>
@@ -31,22 +31,37 @@ import java.util.Arrays;
* @hide
*/
public final class WifiDisplayStatus implements Parcelable {
- private final boolean mEnabled;
+ private final int mFeatureState;
private final int mScanState;
private final int mActiveDisplayState;
private final WifiDisplay mActiveDisplay;
- private final WifiDisplay[] mKnownDisplays;
-
+ private final WifiDisplay[] mAvailableDisplays;
+ private final WifiDisplay[] mRememberedDisplays;
+
+ /** Feature state: Wifi display is not available on this device. */
+ public static final int FEATURE_STATE_UNAVAILABLE = 0;
+ /** Feature state: Wifi display is disabled, probably because Wifi is disabled. */
+ public static final int FEATURE_STATE_DISABLED = 1;
+ /** Feature state: Wifi display is turned off in settings. */
+ public static final int FEATURE_STATE_OFF = 2;
+ /** Feature state: Wifi display is turned on in settings. */
+ public static final int FEATURE_STATE_ON = 3;
+
+ /** Scan state: Not currently scanning. */
public static final int SCAN_STATE_NOT_SCANNING = 0;
+ /** Scan state: Currently scanning. */
public static final int SCAN_STATE_SCANNING = 1;
+ /** Display state: Not connected. */
public static final int DISPLAY_STATE_NOT_CONNECTED = 0;
+ /** Display state: Connecting to active display. */
public static final int DISPLAY_STATE_CONNECTING = 1;
+ /** Display state: Connected to active display. */
public static final int DISPLAY_STATE_CONNECTED = 2;
public static final Creator<WifiDisplayStatus> CREATOR = new Creator<WifiDisplayStatus>() {
public WifiDisplayStatus createFromParcel(Parcel in) {
- boolean enabled = (in.readInt() != 0);
+ int featureState = in.readInt();
int scanState = in.readInt();
int activeDisplayState= in.readInt();
@@ -55,13 +70,18 @@ public final class WifiDisplayStatus implements Parcelable {
activeDisplay = WifiDisplay.CREATOR.createFromParcel(in);
}
- WifiDisplay[] knownDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
- for (int i = 0; i < knownDisplays.length; i++) {
- knownDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+ WifiDisplay[] availableDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
+ for (int i = 0; i < availableDisplays.length; i++) {
+ availableDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+ }
+
+ WifiDisplay[] rememberedDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
+ for (int i = 0; i < rememberedDisplays.length; i++) {
+ rememberedDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
}
- return new WifiDisplayStatus(enabled, scanState, activeDisplayState,
- activeDisplay, knownDisplays);
+ return new WifiDisplayStatus(featureState, scanState, activeDisplayState,
+ activeDisplay, availableDisplays, rememberedDisplays);
}
public WifiDisplayStatus[] newArray(int size) {
@@ -70,33 +90,38 @@ public final class WifiDisplayStatus implements Parcelable {
};
public WifiDisplayStatus() {
- this(false, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
- null, WifiDisplay.EMPTY_ARRAY);
+ this(FEATURE_STATE_UNAVAILABLE, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
+ null, WifiDisplay.EMPTY_ARRAY, WifiDisplay.EMPTY_ARRAY);
}
- public WifiDisplayStatus(boolean enabled, int scanState, int activeDisplayState,
- WifiDisplay activeDisplay, WifiDisplay[] knownDisplays) {
- if (knownDisplays == null) {
- throw new IllegalArgumentException("knownDisplays must not be null");
+ public WifiDisplayStatus(int featureState, int scanState,
+ int activeDisplayState, WifiDisplay activeDisplay,
+ WifiDisplay[] availableDisplays, WifiDisplay[] rememberedDisplays) {
+ if (availableDisplays == null) {
+ throw new IllegalArgumentException("availableDisplays must not be null");
+ }
+ if (rememberedDisplays == null) {
+ throw new IllegalArgumentException("rememberedDisplays must not be null");
}
- mEnabled = enabled;
+ mFeatureState = featureState;
mScanState = scanState;
mActiveDisplayState = activeDisplayState;
mActiveDisplay = activeDisplay;
- mKnownDisplays = knownDisplays;
+ mAvailableDisplays = availableDisplays;
+ mRememberedDisplays = rememberedDisplays;
}
/**
- * Returns true if the Wifi display feature is enabled and available for use.
+ * Returns the state of the Wifi display feature on this device.
* <p>
- * The value of this property reflects whether Wifi and Wifi P2P functions
- * are enabled. Enablement is not directly controllable by the user at this
- * time, except indirectly such as by turning off Wifi altogether.
+ * The value of this property reflects whether the device supports the Wifi display,
+ * whether it has been enabled by the user and whether the prerequisites for
+ * connecting to displays have been met.
* </p>
*/
- public boolean isEnabled() {
- return mEnabled;
+ public int getFeatureState() {
+ return mFeatureState;
}
/**
@@ -127,15 +152,29 @@ public final class WifiDisplayStatus implements Parcelable {
}
/**
- * Gets the list of all known Wifi displays, never null.
+ * Gets the list of all available Wifi displays as reported by the most recent
+ * scan, never null.
+ * <p>
+ * Some of these displays may already be remembered, others may be unknown.
+ * </p>
*/
- public WifiDisplay[] getKnownDisplays() {
- return mKnownDisplays;
+ public WifiDisplay[] getAvailableDisplays() {
+ return mAvailableDisplays;
+ }
+
+ /**
+ * Gets the list of all remembered Wifi displays, never null.
+ * <p>
+ * Not all remembered displays will necessarily be available.
+ * </p>
+ */
+ public WifiDisplay[] getRememberedDisplays() {
+ return mRememberedDisplays;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mEnabled ? 1 : 0);
+ dest.writeInt(mFeatureState);
dest.writeInt(mScanState);
dest.writeInt(mActiveDisplayState);
@@ -146,8 +185,13 @@ public final class WifiDisplayStatus implements Parcelable {
dest.writeInt(0);
}
- dest.writeInt(mKnownDisplays.length);
- for (WifiDisplay display : mKnownDisplays) {
+ dest.writeInt(mAvailableDisplays.length);
+ for (WifiDisplay display : mAvailableDisplays) {
+ display.writeToParcel(dest, flags);
+ }
+
+ dest.writeInt(mRememberedDisplays.length);
+ for (WifiDisplay display : mRememberedDisplays) {
display.writeToParcel(dest, flags);
}
}
@@ -160,11 +204,12 @@ public final class WifiDisplayStatus implements Parcelable {
// For debugging purposes only.
@Override
public String toString() {
- return "WifiDisplayStatus{enabled=" + mEnabled
+ return "WifiDisplayStatus{featureState=" + mFeatureState
+ ", scanState=" + mScanState
+ ", activeDisplayState=" + mActiveDisplayState
+ ", activeDisplay=" + mActiveDisplay
- + ", knownDisplays=" + Arrays.toString(mKnownDisplays)
+ + ", availableDisplays=" + Arrays.toString(mAvailableDisplays)
+ + ", rememberedDisplays=" + Arrays.toString(mRememberedDisplays)
+ "}";
}
}
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index aa392d0..8218e37 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -251,7 +251,7 @@ public class CaptivePortalTracker {
if (visible) {
CharSequence title = r.getString(R.string.wifi_available_sign_in, 0);
- CharSequence details = r.getString(R.string.wifi_available_sign_in_detailed,
+ CharSequence details = r.getString(R.string.network_available_sign_in_detailed,
mNetworkInfo.getExtraInfo());
Notification notification = new Notification();
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index fb7a4f8..446bbf0 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -21,6 +21,7 @@ import android.os.Parcelable;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Objects;
import java.io.CharArrayWriter;
@@ -608,13 +609,13 @@ public class NetworkStats implements Parcelable {
* Return all rows except those attributed to the requested UID; doesn't
* mutate the original structure.
*/
- public NetworkStats withoutUid(int uid) {
+ public NetworkStats withoutUids(int[] uids) {
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
Entry entry = new Entry();
for (int i = 0; i < size; i++) {
entry = getValues(i, entry);
- if (entry.uid != uid) {
+ if (!ArrayUtils.contains(uids, entry.uid)) {
stats.addValues(entry);
}
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 2703f1d..27cabef 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -300,9 +300,10 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
* null if no protocol was negotiated.
*
* @param socket a socket created by this factory.
+ * @throws IllegalArgumentException if the socket was not created by this factory.
*/
public byte[] getNpnSelectedProtocol(Socket socket) {
- return ((OpenSSLSocketImpl) socket).getNpnSelectedProtocol();
+ return castToOpenSSLSocket(socket).getNpnSelectedProtocol();
}
/**
@@ -316,6 +317,38 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
mInsecureFactory = null;
}
+ /**
+ * Enables <a href="http://tools.ietf.org/html/rfc5077#section-3.2">session ticket</a>
+ * support on the given socket.
+ *
+ * @param socket a socket created by this factory
+ * @param useSessionTickets {@code true} to enable session ticket support on this socket.
+ * @throws IllegalArgumentException if the socket was not created by this factory.
+ */
+ public void setUseSessionTickets(Socket socket, boolean useSessionTickets) {
+ castToOpenSSLSocket(socket).setUseSessionTickets(useSessionTickets);
+ }
+
+ /**
+ * Turns on <a href="http://tools.ietf.org/html/rfc6066#section-3">Server
+ * Name Indication (SNI)</a> on a given socket.
+ *
+ * @param socket a socket created by this factory.
+ * @param hostName the desired SNI hostname, null to disable.
+ * @throws IllegalArgumentException if the socket was not created by this factory.
+ */
+ public void setHostname(Socket socket, String hostName) {
+ castToOpenSSLSocket(socket).setHostname(hostName);
+ }
+
+ private static OpenSSLSocketImpl castToOpenSSLSocket(Socket socket) {
+ if (!(socket instanceof OpenSSLSocketImpl)) {
+ throw new IllegalArgumentException("Socket not created by this factory: "
+ + socket);
+ }
+
+ return (OpenSSLSocketImpl) socket;
+ }
/**
* {@inheritDoc}
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
new file mode 100644
index 0000000..64eacbc
--- /dev/null
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import org.apache.harmony.xnet.provider.jsse.TrustManagerImpl;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * X509TrustManager wrapper exposing Android-added features.
+ *
+ * <p> The checkServerTrusted method allows callers to perform additional
+ * verification of certificate chains after they have been successfully
+ * verified by the platform.</p>
+ */
+public class X509TrustManagerExtensions {
+
+ TrustManagerImpl mDelegate;
+
+ /**
+ * Constructs a new X509TrustManagerExtensions wrapper.
+ *
+ * @param tm A {@link X509TrustManager} as returned by TrustManagerFactory.getInstance();
+ * @throws IllegalArgumentException If tm is an unsupported TrustManager type.
+ */
+ public X509TrustManagerExtensions(X509TrustManager tm) throws IllegalArgumentException {
+ if (tm instanceof TrustManagerImpl) {
+ mDelegate = (TrustManagerImpl) tm;
+ } else {
+ throw new IllegalArgumentException("tm is not a supported type of X509TrustManager");
+ }
+ }
+
+ /**
+ * Verifies the given certificate chain.
+ *
+ * <p>See {@link X509TrustManager#checkServerTrusted(X509Certificate[], String)} for a
+ * description of the chain and authType parameters. The final parameter, host, should be the
+ * hostname of the server.</p>
+ *
+ * @throws CertificateException if the chain does not verify correctly.
+ * @return the properly ordered chain used for verification as a list of X509Certificates.
+ */
+ public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
+ String host) throws CertificateException {
+ return mDelegate.checkServerTrusted(chain, authType, host);
+ }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 1607b96..364004b 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -32,6 +32,7 @@ public class Environment {
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
+ private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
/** {@hide} */
public static String DIRECTORY_ANDROID = "Android";
@@ -88,21 +89,30 @@ public class Environment {
private final File mExternalStorageAndroidData;
private final File mExternalStorageAndroidMedia;
private final File mExternalStorageAndroidObb;
+ private final File mMediaStorage;
public UserEnvironment(int userId) {
// See storage config details at http://source.android.com/tech/storage/
String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
+ String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);
+ if (TextUtils.isEmpty(rawMediaStorage)) {
+ rawMediaStorage = "/data/media";
+ }
if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
// Device has emulated storage; external storage paths should have
// userId burned into them.
+ final String rawUserId = Integer.toString(userId);
final File emulatedBase = new File(rawEmulatedStorageTarget);
+ final File mediaBase = new File(rawMediaStorage);
// /storage/emulated/0
- mExternalStorage = buildPath(emulatedBase, Integer.toString(userId));
+ mExternalStorage = buildPath(emulatedBase, rawUserId);
// /storage/emulated/obb
mExternalStorageAndroidObb = buildPath(emulatedBase, "obb");
+ // /data/media/0
+ mMediaStorage = buildPath(mediaBase, rawUserId);
} else {
// Device has physical external storage; use plain paths.
@@ -115,6 +125,8 @@ public class Environment {
mExternalStorage = new File(rawExternalStorage);
// /storage/sdcard0/Android/obb
mExternalStorageAndroidObb = buildPath(mExternalStorage, DIRECTORY_ANDROID, "obb");
+ // /data/media
+ mMediaStorage = new File(rawMediaStorage);
}
mExternalStorageAndroidData = buildPath(mExternalStorage, DIRECTORY_ANDROID, "data");
@@ -152,6 +164,10 @@ public class Environment {
public File getExternalStorageAppCacheDirectory(String packageName) {
return new File(new File(mExternalStorageAndroidData, packageName), "cache");
}
+
+ public File getMediaStorageDirectory() {
+ return mMediaStorage;
+ }
}
/**
@@ -198,7 +214,8 @@ public class Environment {
* @hide
*/
public static File getMediaStorageDirectory() {
- return MEDIA_STORAGE_DIRECTORY;
+ throwIfSystem();
+ return sCurrentUser.getMediaStorageDirectory();
}
/**
@@ -231,10 +248,6 @@ public class Environment {
private static final File SECURE_DATA_DIRECTORY
= getDirectory("ANDROID_SECURE_DATA", "/data/secure");
- /** @hide */
- private static final File MEDIA_STORAGE_DIRECTORY
- = getDirectory("MEDIA_STORAGE", "/data/media");
-
private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index c7a8493..0798913 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -19,6 +19,7 @@ package android.os;
import android.os.ParcelFileDescriptor;
import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
/**
* {@hide}
@@ -27,7 +28,8 @@ interface IUserManager {
UserInfo createUser(in String name, int flags);
boolean removeUser(int userHandle);
void setUserName(int userHandle, String name);
- ParcelFileDescriptor setUserIcon(int userHandle);
+ void setUserIcon(int userHandle, in Bitmap icon);
+ Bitmap getUserIcon(int userHandle);
List<UserInfo> getUsers();
UserInfo getUserInfo(int userHandle);
void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index de8e78c..b532966 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -18,6 +18,8 @@ package android.os;
import com.android.internal.R;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.content.res.Resources;
import android.util.Log;
import java.util.List;
@@ -40,8 +42,9 @@ public class UserManager {
/**
* Returns whether the system supports multiple users.
* @return true if multiple users can be created, false if it is a single user device.
+ * @hide
*/
- public boolean supportsMultipleUsers() {
+ public static boolean supportsMultipleUsers() {
return getMaxSupportedUsers() > 1;
}
@@ -55,8 +58,9 @@ public class UserManager {
}
/**
- * Returns the user name of the user making this call.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * Returns the user name of the user making this call. This call is only
+ * available to applications on the system image; it requires the
+ * MANAGE_USERS permission.
* @return the user name
*/
public String getUserName() {
@@ -151,16 +155,30 @@ public class UserManager {
}
/**
- * Returns a file descriptor for the user's photo. PNG data can be written into this file.
+ * Sets the user's photo.
* @param userHandle the user for whom to change the photo.
- * @return a {@link ParcelFileDescriptor} to which to write the photo.
+ * @param icon the bitmap to set as the photo.
* @hide
*/
- public ParcelFileDescriptor setUserIcon(int userHandle) {
+ public void setUserIcon(int userHandle, Bitmap icon) {
try {
- return mService.setUserIcon(userHandle);
+ mService.setUserIcon(userHandle, icon);
} catch (RemoteException re) {
Log.w(TAG, "Could not set the user icon ", re);
+ }
+ }
+
+ /**
+ * Returns a file descriptor for the user's photo. PNG data can be read from this file.
+ * @param userHandle the user whose photo we want to read.
+ * @return a {@link Bitmap} of the user's photo, or null if there's no photo.
+ * @hide
+ */
+ public Bitmap getUserIcon(int userHandle) {
+ try {
+ return mService.getUserIcon(userHandle);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get the user icon ", re);
return null;
}
}
@@ -215,8 +233,9 @@ public class UserManager {
* @hide
* @return a value greater than or equal to 1
*/
- public int getMaxSupportedUsers() {
- return mContext.getResources().getInteger(R.integer.config_multiuserMaximumUsers);
+ public static int getMaxSupportedUsers() {
+ return SystemProperties.getInt("fw.max_users",
+ Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a182234..bb118b2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -214,6 +214,21 @@ public final class Settings {
"android.settings.BLUETOOTH_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of Wifi Displays.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_WIFI_DISPLAY_SETTINGS =
+ "android.settings.WIFI_DISPLAY_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of date and time.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -1338,7 +1353,7 @@ public final class Settings {
/** @deprecated - Do not use */
@Deprecated
public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
- /* intentionally empty */
+ setShowGTalkServiceStatusForUser(cr, flag, UserHandle.myUserId());
}
/**
@@ -5540,6 +5555,13 @@ public final class Settings {
"web_autofill_query_url";
/**
+ * Whether Wifi display is enabled/disabled
+ * 0=disabled. 1=enabled.
+ * @hide
+ */
+ public static final String WIFI_DISPLAY_ON = "wifi_display_on";
+
+ /**
* Whether to notify the user of open networks.
* <p>
* If not connected and the scan results have an open network, we will
@@ -5614,6 +5636,13 @@ public final class Settings {
"wifi_supplicant_scan_interval_ms";
/**
+ * The interval in milliseconds to scan at supplicant when p2p is connected
+ * @hide
+ */
+ public static final String WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS =
+ "wifi_scan_interval_p2p_connected_ms";
+
+ /**
* Whether the Wi-Fi watchdog is enabled.
*/
public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index ba2ac67..4a23d39 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -22,7 +22,6 @@ import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.ActionMode;
@@ -40,12 +39,16 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PolicyManager;
/**
- * Extend this class to implement a custom screensaver.
+ * Extend this class to implement a custom Dream.
+ *
+ * <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a
+ * desk dock. Dreams provide another modality for apps to express themselves, tailored for
+ * an exhibition/lean-back experience.</p>
*/
public class Dream extends Service implements Window.Callback {
private final static boolean DEBUG = true;
- private final static String TAG = "Dream";
-
+ private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
+
/**
* The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the
@@ -60,28 +63,43 @@ public class Dream extends Service implements Window.Callback {
public static final String METADATA_NAME_CONFIG_ACTIVITY =
"android.service.dreams.config_activity";
- private Window mWindow;
+ /**
+ * Broadcast Action: Sent after the system starts dreaming.
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ * It is only sent to registered receivers.</p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED";
+ /**
+ * Broadcast Action: Sent after the system stops dreaming.
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ * It is only sent to registered receivers.</p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED";
+
+ private final Handler mHandler = new Handler();
+ private IBinder mWindowToken;
+ private Window mWindow;
private WindowManager mWindowManager;
private IDreamManager mSandman;
-
private boolean mInteractive;
-
- final Handler mHandler = new Handler();
-
- boolean mFinished = false;
+ private boolean mFinished;
// begin Window.Callback methods
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on keyEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on keyEvent");
+ safelyFinish();
return true;
} else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (DEBUG) Slog.v(TAG, "finishing on back key");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on back key");
+ safelyFinish();
return true;
}
return mWindow.superDispatchKeyEvent(event);
@@ -90,8 +108,8 @@ public class Dream extends Service implements Window.Callback {
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on keyShortcutEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on keyShortcutEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchKeyShortcutEvent(event);
@@ -102,8 +120,8 @@ public class Dream extends Service implements Window.Callback {
// TODO: create more flexible version of mInteractive that allows clicks
// but finish()es on any other kind of activity
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on touchEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on touchEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchTouchEvent(event);
@@ -112,8 +130,8 @@ public class Dream extends Service implements Window.Callback {
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on trackballEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on trackballEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchTrackballEvent(event);
@@ -122,8 +140,8 @@ public class Dream extends Service implements Window.Callback {
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
if (!mInteractive) {
- if (DEBUG) Slog.v(TAG, "finishing on genericMotionEvent");
- finish();
+ if (DEBUG) Slog.v(TAG, "Finishing on genericMotionEvent");
+ safelyFinish();
return true;
}
return mWindow.superDispatchGenericMotionEvent(event);
@@ -212,30 +230,9 @@ public class Dream extends Service implements Window.Callback {
public Window getWindow() {
return mWindow;
}
-
- /**
- * Called when this Dream is constructed. Place your initialization here.
- *
- * Subclasses must call through to the superclass implementation.
- */
- @Override
- public void onCreate() {
- super.onCreate();
-
- if (DEBUG) Slog.v(TAG, "Dream created on thread " + Thread.currentThread().getId());
-
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
- }
-
- /**
- * Called when this Dream is started.
- */
- public void onStart() {
- // hook for subclasses
- }
/**
- * Inflate a layout resource and set it to be the content view for this Dream.
+ * Inflates a layout resource and set it to be the content view for this Dream.
* Behaves similarly to {@link android.app.Activity#setContentView(int)}.
*
* @param layoutResID Resource ID to be inflated.
@@ -248,7 +245,7 @@ public class Dream extends Service implements Window.Callback {
}
/**
- * Set a view to be the content view for this Dream.
+ * Sets a view to be the content view for this Dream.
* Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
* including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
*
@@ -262,7 +259,7 @@ public class Dream extends Service implements Window.Callback {
}
/**
- * Set a view to be the content view for this Dream.
+ * Sets a view to be the content view for this Dream.
* Behaves similarly to
* {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
*
@@ -277,7 +274,7 @@ public class Dream extends Service implements Window.Callback {
}
/**
- * Add a view to the Dream's window, leaving other content views in place.
+ * Adds a view to the Dream's window, leaving other content views in place.
*
* @param view The desired content to display.
* @param params Layout parameters for the view.
@@ -285,21 +282,27 @@ public class Dream extends Service implements Window.Callback {
public void addContentView(View view, ViewGroup.LayoutParams params) {
getWindow().addContentView(view, params);
}
-
+
/**
- * @param mInteractive the mInteractive to set
+ * Marks this dream as interactive to receive input events.
+ *
+ * <p>Non-interactive dreams (default) will dismiss on the first input event.</p>
+ *
+ * <p>Interactive dreams should call {@link #finish()} to dismiss themselves.</p>
+ *
+ * @param interactive True if this dream will handle input events.
*/
- public void setInteractive(boolean mInteractive) {
- this.mInteractive = mInteractive;
+ public void setInteractive(boolean interactive) {
+ mInteractive = interactive;
}
/**
- * @return the mInteractive
+ * Returns whether or not this dream is interactive.
*/
public boolean isInteractive() {
return mInteractive;
}
-
+
/** Convenience method for setting View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. */
protected void lightsOut() {
// turn the lights down low
@@ -319,14 +322,29 @@ public class Dream extends Service implements Window.Callback {
public View findViewById(int id) {
return getWindow().findViewById(id);
}
-
+
/**
- * Called when this Dream is being removed from the screen and stopped.
+ * Called when this Dream is constructed. Place your initialization here.
+ *
+ * Subclasses must call through to the superclass implementation.
*/
@Override
- public void onDestroy() {
- super.onDestroy();
- mWindowManager.removeView(mWindow.getDecorView());
+ public void onCreate() {
+ if (DEBUG) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId());
+ super.onCreate();
+ loadSandman();
+ }
+
+ /**
+ * Called when this Dream is started.
+ */
+ public void onStart() {
+ // hook for subclasses
+ Slog.v(TAG, "called Dream.onStart()");
+ }
+
+ private void loadSandman() {
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
}
/**
@@ -335,16 +353,21 @@ public class Dream extends Service implements Window.Callback {
* @param windowToken Binder to attach to the window to allow access to the correct window type.
* @hide
*/
- final /*package*/ void attach(IBinder windowToken) {
- if (DEBUG) Slog.v(TAG, "Dream attached on thread " + Thread.currentThread().getId());
-
+ private final void attach(IBinder windowToken) {
+ if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
+
+ if (mSandman == null) {
+ Slog.w(TAG, "No dream manager found, super.onCreate may not have been called");
+ loadSandman();
+ }
+ mWindowToken = windowToken;
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
- if (DEBUG) Slog.v(TAG, "attaching window token: " + windowToken
- + " to window of type " + WindowManager.LayoutParams.TYPE_DREAM);
+ if (DEBUG) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
+ windowToken, WindowManager.LayoutParams.TYPE_DREAM));
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
@@ -355,58 +378,105 @@ public class Dream extends Service implements Window.Callback {
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
);
mWindow.setAttributes(lp);
-
- //WindowManagerImpl.getDefault().addView(mWindow.getDecorView(), lp);
-
- if (DEBUG) Slog.v(TAG, "created and attached window: " + mWindow);
+
+ if (DEBUG) Slog.v(TAG, "Created and attached window: " + mWindow);
mWindow.setWindowManager(null, windowToken, "dream", true);
mWindowManager = mWindow.getWindowManager();
-
- // now make it visible
+
+ // now make it visible (on the ui thread)
mHandler.post(new Runnable(){
@Override
public void run() {
- if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId());
+ if (DEBUG) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ try {
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ } catch (Throwable t) {
+ Slog.w("Crashed adding window view", t);
+ safelyFinish();
+ return;
+ }
// start it up
- onStart();
+ try {
+ onStart();
+ } catch (Throwable t) {
+ Slog.w("Crashed in onStart()", t);
+ safelyFinish();
+ }
}});
}
-
+
+ private void safelyFinish() {
+ if (DEBUG) Slog.v(TAG, "safelyFinish()");
+ try {
+ finish();
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed in safelyFinish()", t);
+ finishInternal();
+ return;
+ }
+
+ if (!mFinished) {
+ Slog.w(TAG, "Bad dream, did not call super.finish()");
+ finishInternal();
+ }
+ }
+
/**
- * Stop the dream and wake up.
- *
- * After this method is called, the service will be stopped.
+ * Stops the dream, detaches from the window, and wakes up.
+ *
+ * Subclasses must call through to the superclass implementation.
+ *
+ * <p>After this method is called, the service will be stopped.</p>
*/
public void finish() {
+ if (DEBUG) Slog.v(TAG, "finish()");
+ finishInternal();
+ }
+
+ private void finishInternal() {
+ if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
if (mFinished) return;
try {
- mSandman.awaken(); // assuming we were started by the DreamManager
- stopSelf(); // if launched via any other means
mFinished = true;
- } catch (RemoteException ex) {
- // sigh
+
+ if (mSandman != null) {
+ mSandman.awakenSelf(mWindowToken);
+ } else {
+ Slog.w(TAG, "No dream manager found");
+ }
+ stopSelf(); // if launched via any other means
+
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed in finishInternal()", t);
}
}
- class IDreamServiceWrapper extends IDreamService.Stub {
- public IDreamServiceWrapper() {
- }
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Slog.v(TAG, "onDestroy()");
+ super.onDestroy();
- public void attach(IBinder windowToken) {
- Dream.this.attach(windowToken);
+ if (DEBUG) Slog.v(TAG, "Removing window");
+ try {
+ mWindowManager.removeView(mWindow.getDecorView());
+ } catch (Throwable t) {
+ Slog.w(TAG, "Crashed removing window view", t);
}
}
- /**
- * Implement to return the implementation of the internal accessibility
- * service interface. Subclasses should not override.
- */
@Override
public final IBinder onBind(Intent intent) {
- return new IDreamServiceWrapper();
+ if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ return new DreamServiceWrapper();
}
+
+ private class DreamServiceWrapper extends IDreamService.Stub {
+ public void attach(IBinder windowToken) {
+ Dream.this.attach(windowToken);
+ }
+ }
+
}
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
deleted file mode 100644
index 4aa1cbb..0000000
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ /dev/null
@@ -1,247 +0,0 @@
-package android.service.dreams;
-
-import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
-import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import android.app.ActivityManagerNative;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-/**
- *
- * @hide
- *
- */
-
-public class DreamManagerService
- extends IDreamManager.Stub
- implements ServiceConnection
-{
- private static final boolean DEBUG = true;
- private static final String TAG = "DreamManagerService";
-
- final Object mLock = new Object[0];
-
- private Context mContext;
- private IWindowManager mIWindowManager;
-
- private ComponentName mCurrentDreamComponent;
- private IDreamService mCurrentDream;
- private Binder mCurrentDreamToken;
- private int mCurrentUserId;
-
- public DreamManagerService(Context context) {
- if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
- mContext = context;
- mIWindowManager = WindowManagerGlobal.getWindowManagerService();
- }
-
- private void checkPermission(String permission) {
- if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
- throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
- + ", must have permission " + permission);
- }
- }
-
- // IDreamManager method
- @Override
- public void dream() {
- ComponentName[] dreams = getDreamComponentsForUser(mCurrentUserId);
- ComponentName name = dreams != null && dreams.length > 0 ? dreams[0] : null;
- if (name != null) {
- synchronized (mLock) {
- final long ident = Binder.clearCallingIdentity();
- try {
- bindDreamComponentL(name, false);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
- }
-
- // IDreamManager method
- @Override
- public void setDreamComponents(ComponentName[] componentNames) {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- SCREENSAVER_COMPONENTS,
- componentsToString(componentNames),
- UserHandle.getCallingUserId());
- }
-
- private static String componentsToString(ComponentName[] componentNames) {
- StringBuilder names = new StringBuilder();
- if (componentNames != null) {
- for (ComponentName componentName : componentNames) {
- if (names.length() > 0)
- names.append(',');
- names.append(componentName.flattenToString());
- }
- }
- return names.toString();
- }
-
- private static ComponentName[] componentsFromString(String names) {
- String[] namesArray = names.split(",");
- ComponentName[] componentNames = new ComponentName[namesArray.length];
- for (int i = 0; i < namesArray.length; i++)
- componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
- return componentNames;
- }
-
- // IDreamManager method
- @Override
- public ComponentName[] getDreamComponents() {
- return getDreamComponentsForUser(UserHandle.getCallingUserId());
- }
-
- private ComponentName[] getDreamComponentsForUser(int userId) {
- String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- SCREENSAVER_COMPONENTS,
- userId);
- return names == null ? null : componentsFromString(names);
- }
-
- // IDreamManager method
- @Override
- public ComponentName getDefaultDreamComponent() {
- String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- SCREENSAVER_DEFAULT_COMPONENT,
- UserHandle.getCallingUserId());
- return name == null ? null : ComponentName.unflattenFromString(name);
- }
-
- // IDreamManager method
- @Override
- public void testDream(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "startDream name=" + name
- + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-// checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
- synchronized (mLock) {
- final long ident = Binder.clearCallingIdentity();
- try {
- bindDreamComponentL(name, true);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- // IDreamManager method
- @Override
- public void awaken() {
- if (DEBUG) Slog.v(TAG, "awaken()");
- synchronized (mLock) {
- if (mCurrentDream != null) {
- if (DEBUG) Slog.v(TAG, "disconnecting: " + mCurrentDreamComponent + " service: " + mCurrentDream);
- mContext.unbindService(this);
- mCurrentDream = null;
- mCurrentDreamToken = null;
- }
- }
- }
-
- // IDreamManager method
- @Override
- public boolean isDreaming() {
- synchronized (mLock) {
- return mCurrentDreamToken != null;
- }
- }
-
- public void bindDreamComponentL(ComponentName componentName, boolean test) {
- if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName
- + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-
- Intent intent = new Intent(Intent.ACTION_MAIN)
- .setComponent(componentName)
- .addFlags(
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- )
- .putExtra("android.dreams.TEST", test);
-
- mCurrentDreamComponent = componentName;
- mCurrentDreamToken = new Binder();
- try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
- + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
- mIWindowManager.addWindowToken(mCurrentDreamToken,
- WindowManager.LayoutParams.TYPE_DREAM);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to add window token. Proceed at your own risk.");
- }
-
- if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
- Slog.w(TAG, "unable to bind service: " + componentName);
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Slog.v(TAG, "connected to dream: " + name + " binder=" + service + " thread=" + Thread.currentThread().getId());
-
- mCurrentDream = IDreamService.Stub.asInterface(service);
- try {
- if (DEBUG) Slog.v(TAG, "attaching with token:" + mCurrentDreamToken);
- mCurrentDream.attach(mCurrentDreamToken);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Unable to send window token to dream:" + ex);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream);
- // Only happens in exceptional circumstances
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
- pw.println("Dreamland:");
- pw.print(" component="); pw.println(mCurrentDreamComponent);
- pw.print(" token="); pw.println(mCurrentDreamToken);
- pw.print(" dream="); pw.println(mCurrentDream);
- }
-
- public void systemReady() {
-
- // dream settings are kept per user, so keep track of current user
- try {
- mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
- } catch (RemoteException e) {
- Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
- }
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- if (DEBUG) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
- }
- }}, filter);
-
- if (DEBUG) Slog.v(TAG, "ready to dream!");
- }
-
-}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index b6fcdf0..bd1c524 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -19,6 +19,7 @@ package android.service.dreams;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.content.ComponentName;
+import android.os.IBinder;
/** @hide */
interface IDreamManager {
@@ -29,4 +30,5 @@ interface IDreamManager {
ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
+ void awakenSelf(in IBinder token);
} \ No newline at end of file
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index bbaa173..df8c4c6 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -17,7 +17,6 @@
package android.text;
-import android.util.LocaleUtil;
import android.view.View;
/**
@@ -242,7 +241,7 @@ public class TextDirectionHeuristics {
@Override
protected boolean defaultIsRtl() {
- final int dir = LocaleUtil.getLayoutDirectionFromLocale(java.util.Locale.getDefault());
+ final int dir = TextUtils.getLayoutDirectionFromLocale(java.util.Locale.getDefault());
return (dir == View.LAYOUT_DIRECTION_RTL);
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 987062a..1508d10 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -46,11 +46,14 @@ import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.util.Printer;
+import android.view.View;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+import libcore.icu.ICU;
import java.lang.reflect.Array;
import java.util.Iterator;
+import java.util.Locale;
import java.util.regex.Pattern;
public class TextUtils {
@@ -1706,10 +1709,64 @@ public class TextUtils {
return (int) (range & 0x00000000FFFFFFFFL);
}
+ /**
+ * Return the layout direction for a given Locale
+ *
+ * @param locale the Locale for which we want the layout direction. Can be null.
+ * @return the layout direction. This may be one of:
+ * {@link android.view.View#LAYOUT_DIRECTION_LTR} or
+ * {@link android.view.View#LAYOUT_DIRECTION_RTL}.
+ *
+ * Be careful: this code will need to be updated when vertical scripts will be supported
+ */
+ public static int getLayoutDirectionFromLocale(Locale locale) {
+ if (locale != null && !locale.equals(Locale.ROOT)) {
+ final String scriptSubtag = ICU.getScript(ICU.addLikelySubtags(locale.toString()));
+ if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
+
+ if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
+ scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
+ return View.LAYOUT_DIRECTION_RTL;
+ }
+ }
+
+ return View.LAYOUT_DIRECTION_LTR;
+ }
+
+ /**
+ * Fallback algorithm to detect the locale direction. Rely on the fist char of the
+ * localized locale name. This will not work if the localized locale name is in English
+ * (this is the case for ICU 4.4 and "Urdu" script)
+ *
+ * @param locale
+ * @return the layout direction. This may be one of:
+ * {@link View#LAYOUT_DIRECTION_LTR} or
+ * {@link View#LAYOUT_DIRECTION_RTL}.
+ *
+ * Be careful: this code will need to be updated when vertical scripts will be supported
+ *
+ * @hide
+ */
+ private static int getLayoutDirectionFromFirstChar(Locale locale) {
+ switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ return View.LAYOUT_DIRECTION_RTL;
+
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ default:
+ return View.LAYOUT_DIRECTION_LTR;
+ }
+ }
+
private static Object sLock = new Object();
+
private static char[] sTemp = null;
private static String[] EMPTY_STRING_ARRAY = new String[]{};
private static final char ZWNBS_CHAR = '\uFEFF';
+
+ private static String ARAB_SCRIPT_SUBTAG = "Arab";
+ private static String HEBR_SCRIPT_SUBTAG = "Hebr";
}
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 524f941..c36273e 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -35,10 +35,18 @@ import java.text.SimpleDateFormat;
Utility class for producing strings with formatted date/time.
<p>
- This class takes as inputs a format string and a representation of a date/time.
- The format string controls how the output is generated.
+ Most callers should avoid supplying their own format strings to this
+ class' {@code format} methods and rely on the correctly localized ones
+ supplied by the system. This class' factory methods return
+ appropriately-localized {@link java.text.DateFormat} instances, suitable
+ for both formatting and parsing dates. For the canonical documentation
+ of format strings, see {@link java.text.SimpleDateFormat}.
</p>
<p>
+ The format methods in this class takes as inputs a format string and a representation of a date/time.
+ The format string controls how the output is generated.
+ This class only supports a subset of the full Unicode specification.
+ Use {@link java.text.SimpleDateFormat} if you need more.
Formatting characters may be repeated in order to get more detailed representations
of that field. For instance, the format character &apos;M&apos; is used to
represent the month. Depending on how many times that character is repeated
@@ -152,7 +160,8 @@ public class DateFormat {
public static final char MINUTE = 'm';
/**
- This designator indicates the month of the year
+ This designator indicates the month of the year. See also
+ {@link #STANDALONE_MONTH}.
Examples for September:
M -> 9
@@ -163,6 +172,14 @@ public class DateFormat {
public static final char MONTH = 'M';
/**
+ This designator indicates the standalone month of the year,
+ necessary in some format strings in some languages. For
+ example, Russian distinguishes between the "June" in
+ "June" and that in "June 2010".
+ */
+ public static final char STANDALONE_MONTH = 'L';
+
+ /**
This designator indicates the seconds of the minute.
Examples for 7 seconds past the minute:
@@ -374,7 +391,7 @@ public class DateFormat {
index++;
}
- if (!foundMonth && (c == MONTH)) {
+ if (!foundMonth && (c == MONTH || c == STANDALONE_MONTH)) {
foundMonth = true;
order[index] = MONTH;
index++;
@@ -494,9 +511,10 @@ public class DateFormat {
break;
case MONTH:
- replacement = getMonthString(inDate, count);
+ case STANDALONE_MONTH:
+ replacement = getMonthString(inDate, count, c);
break;
-
+
case SECONDS:
replacement = zeroPad(inDate.get(Calendar.SECOND), count);
break;
@@ -527,14 +545,19 @@ public class DateFormat {
return s.toString();
}
- private static final String getMonthString(Calendar inDate, int count) {
+ private static final String getMonthString(Calendar inDate, int count, int kind) {
+ boolean standalone = (kind == STANDALONE_MONTH);
int month = inDate.get(Calendar.MONTH);
- if (count >= 4)
- return DateUtils.getMonthString(month, DateUtils.LENGTH_LONG);
- else if (count == 3)
- return DateUtils.getMonthString(month, DateUtils.LENGTH_MEDIUM);
- else {
+ if (count >= 4) {
+ return standalone
+ ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_LONG)
+ : DateUtils.getMonthString(month, DateUtils.LENGTH_LONG);
+ } else if (count == 3) {
+ return standalone
+ ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_MEDIUM)
+ : DateUtils.getMonthString(month, DateUtils.LENGTH_MEDIUM);
+ } else {
// Calendar.JANUARY == 0, so add 1 to month.
return zeroPad(month+1, count);
}
@@ -574,7 +597,8 @@ public class DateFormat {
private static final String getYearString(Calendar inDate, int count) {
int year = inDate.get(Calendar.YEAR);
- return (count <= 2) ? zeroPad(year % 100, 2) : String.valueOf(year);
+ return (count <= 2) ? zeroPad(year % 100, 2)
+ : String.format(Locale.getDefault(), "%d", year);
}
private static final int appendQuotedText(SpannableStringBuilder s, int i, int len) {
@@ -615,17 +639,6 @@ public class DateFormat {
}
private static final String zeroPad(int inValue, int inMinDigits) {
- String val = String.valueOf(inValue);
-
- if (val.length() < inMinDigits) {
- char[] buf = new char[inMinDigits];
-
- for (int i = 0; i < inMinDigits; i++)
- buf[i] = '0';
-
- val.getChars(0, val.length(), buf, inMinDigits - val.length());
- val = new String(buf);
- }
- return val;
+ return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
}
}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 0babcc5..1060bd8 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -45,7 +45,6 @@ public class DateUtils
private static final String FAST_FORMAT_HMMSS = "%1$d:%2$02d:%3$02d";
private static final String FAST_FORMAT_MMSS = "%1$02d:%2$02d";
- private static final char TIME_PADDING = '0';
private static final char TIME_SEPARATOR = ':';
@@ -648,33 +647,36 @@ public class DateUtils
}
}
+ private static void append(StringBuilder sb, long value, boolean pad, char zeroDigit) {
+ if (value < 10) {
+ if (pad) {
+ sb.append(zeroDigit);
+ }
+ } else {
+ sb.append((char) (zeroDigit + (value / 10)));
+ }
+ sb.append((char) (zeroDigit + (value % 10)));
+ }
+
/**
- * Fast formatting of h:mm:ss
+ * Fast formatting of h:mm:ss.
*/
private static String formatElapsedTime(StringBuilder recycle, String format, long hours,
long minutes, long seconds) {
if (FAST_FORMAT_HMMSS.equals(format)) {
+ char zeroDigit = LocaleData.get(Locale.getDefault()).zeroDigit;
+
StringBuilder sb = recycle;
if (sb == null) {
sb = new StringBuilder(8);
} else {
sb.setLength(0);
}
- sb.append(hours);
+ append(sb, hours, false, zeroDigit);
sb.append(TIME_SEPARATOR);
- if (minutes < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(minutes / 10));
- }
- sb.append(toDigitChar(minutes % 10));
+ append(sb, minutes, true, zeroDigit);
sb.append(TIME_SEPARATOR);
- if (seconds < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(seconds / 10));
- }
- sb.append(toDigitChar(seconds % 10));
+ append(sb, seconds, true, zeroDigit);
return sb.toString();
} else {
return String.format(format, hours, minutes, seconds);
@@ -682,40 +684,28 @@ public class DateUtils
}
/**
- * Fast formatting of m:ss
+ * Fast formatting of mm:ss.
*/
private static String formatElapsedTime(StringBuilder recycle, String format, long minutes,
long seconds) {
if (FAST_FORMAT_MMSS.equals(format)) {
+ char zeroDigit = LocaleData.get(Locale.getDefault()).zeroDigit;
+
StringBuilder sb = recycle;
if (sb == null) {
sb = new StringBuilder(8);
} else {
sb.setLength(0);
}
- if (minutes < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(minutes / 10));
- }
- sb.append(toDigitChar(minutes % 10));
+ append(sb, minutes, false, zeroDigit);
sb.append(TIME_SEPARATOR);
- if (seconds < 10) {
- sb.append(TIME_PADDING);
- } else {
- sb.append(toDigitChar(seconds / 10));
- }
- sb.append(toDigitChar(seconds % 10));
+ append(sb, seconds, true, zeroDigit);
return sb.toString();
} else {
return String.format(format, minutes, seconds);
}
}
- private static char toDigitChar(long digit) {
- return (char) (digit + '0');
- }
-
/**
* Format a date / time such that if the then is on the same day as now, it shows
* just the time and if it's a different day, it shows just the date.
@@ -1387,6 +1377,14 @@ public class DateUtils
String endMonthDayString = isInstant ? null : endDate.format(MONTH_DAY_FORMAT);
String endYearString = isInstant ? null : endDate.format(YEAR_FORMAT);
+ String startStandaloneMonthString = startMonthString;
+ String endStandaloneMonthString = endMonthString;
+ // We need standalone months for these strings in Persian (fa): http://b/6811327
+ if (!numericDate && !abbrevMonth && Locale.getDefault().getLanguage().equals("fa")) {
+ startStandaloneMonthString = startDate.format("%-B");
+ endStandaloneMonthString = endDate.format("%-B");
+ }
+
if (startMonthNum != endMonthNum) {
// Same year, different month.
// Example: "October 28 - November 3"
@@ -1407,7 +1405,8 @@ public class DateUtils
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
- endYearString, endTimeString);
+ endYearString, endTimeString,
+ startStandaloneMonthString, endStandaloneMonthString);
}
if (startDay != endDay) {
@@ -1426,7 +1425,8 @@ public class DateUtils
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
- endYearString, endTimeString);
+ endYearString, endTimeString,
+ startStandaloneMonthString, endStandaloneMonthString);
}
// Same start and end day
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 45d5a70..5ef86b1 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -151,6 +151,9 @@ public class Time {
private static String sDateTimeFormat;
private static String sAm;
private static String sPm;
+ private static char sZeroDigit;
+
+ // Referenced by native code.
private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y";
/**
@@ -323,6 +326,7 @@ public class Time {
sAm = localeData.amPm[0];
sPm = localeData.amPm[1];
+ sZeroDigit = localeData.zeroDigit;
sShortMonths = localeData.shortMonthNames;
sLongMonths = localeData.longMonthNames;
@@ -338,12 +342,32 @@ public class Time {
sLocale = locale;
}
- return format1(format);
+ String result = format1(format);
+ if (sZeroDigit != '0') {
+ result = localizeDigits(result);
+ }
+ return result;
}
}
native private String format1(String format);
+ // TODO: unify this with java.util.Formatter's copy.
+ private String localizeDigits(String s) {
+ int length = s.length();
+ int offsetToLocalizedDigits = sZeroDigit - '0';
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ char ch = s.charAt(i);
+ if (ch >= '0' && ch <= '9') {
+ ch += offsetToLocalizedDigits;
+ }
+ result.append(ch);
+ }
+ return result.toString();
+ }
+
+
/**
* Return the current time in YYYYMMDDTHHMMSS<tz> format
*/
@@ -673,7 +697,7 @@ public class Time {
int minutes = (offset % 3600) / 60;
int hours = offset / 3600;
- return String.format("%s%s%02d:%02d", base, sign, hours, minutes);
+ return String.format(Locale.US, "%s%s%02d:%02d", base, sign, hours, minutes);
}
}
diff --git a/core/java/android/util/LocaleUtil.java b/core/java/android/util/LocaleUtil.java
deleted file mode 100644
index 60526e1..0000000
--- a/core/java/android/util/LocaleUtil.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import java.util.Locale;
-
-import android.view.View;
-import libcore.icu.ICU;
-
-/**
- * Various utilities for Locales
- *
- */
-public class LocaleUtil {
-
- private LocaleUtil() { /* cannot be instantiated */ }
-
- private static String ARAB_SCRIPT_SUBTAG = "Arab";
- private static String HEBR_SCRIPT_SUBTAG = "Hebr";
-
- /**
- * Return the layout direction for a given Locale
- *
- * @param locale the Locale for which we want the layout direction. Can be null.
- * @return the layout direction. This may be one of:
- * {@link View#LAYOUT_DIRECTION_LTR} or
- * {@link View#LAYOUT_DIRECTION_RTL}.
- *
- * Be careful: this code will need to be updated when vertical scripts will be supported
- */
- public static int getLayoutDirectionFromLocale(Locale locale) {
- if (locale != null && !locale.equals(Locale.ROOT)) {
- final String scriptSubtag = ICU.getScript(ICU.addLikelySubtags(locale.toString()));
- if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
-
- if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
- scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
- return View.LAYOUT_DIRECTION_RTL;
- }
- }
-
- return View.LAYOUT_DIRECTION_LTR;
- }
-
- /**
- * Fallback algorithm to detect the locale direction. Rely on the fist char of the
- * localized locale name. This will not work if the localized locale name is in English
- * (this is the case for ICU 4.4 and "Urdu" script)
- *
- * @param locale
- * @return the layout direction. This may be one of:
- * {@link View#LAYOUT_DIRECTION_LTR} or
- * {@link View#LAYOUT_DIRECTION_RTL}.
- *
- * Be careful: this code will need to be updated when vertical scripts will be supported
- *
- * @hide
- */
- private static int getLayoutDirectionFromFirstChar(Locale locale) {
- switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return View.LAYOUT_DIRECTION_RTL;
-
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- default:
- return View.LAYOUT_DIRECTION_LTR;
- }
- }
-}
diff --git a/core/java/android/util/PropertyValueModel.java b/core/java/android/util/PropertyValueModel.java
deleted file mode 100755
index eb9c47d..0000000
--- a/core/java/android/util/PropertyValueModel.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-/**
- * A value model for a {@link Property property} of a host object. This class can be used for
- * both reflective and non-reflective property implementations.
- *
- * @param <H> the host type, where the host is the object that holds this property
- * @param <T> the value type
- *
- * @see Property
- * @see ValueModel
- */
-public class PropertyValueModel<H, T> extends ValueModel<T> {
- private final H mHost;
- private final Property<H, T> mProperty;
-
- private PropertyValueModel(H host, Property<H, T> property) {
- mProperty = property;
- mHost = host;
- }
-
- /**
- * Returns the host.
- *
- * @return the host
- */
- public H getHost() {
- return mHost;
- }
-
- /**
- * Returns the property.
- *
- * @return the property
- */
- public Property<H, T> getProperty() {
- return mProperty;
- }
-
- @Override
- public Class<T> getType() {
- return mProperty.getType();
- }
-
- @Override
- public T get() {
- return mProperty.get(mHost);
- }
-
- @Override
- public void set(T value) {
- mProperty.set(mHost, value);
- }
-
- /**
- * Return an appropriate PropertyValueModel for this host and property.
- *
- * @param host the host
- * @param property the property
- * @return the value model
- */
- public static <H, T> PropertyValueModel<H, T> of(H host, Property<H, T> property) {
- return new PropertyValueModel<H, T>(host, property);
- }
-
- /**
- * Return a PropertyValueModel for this {@code host} and a
- * reflective property, constructed from this {@code propertyType} and {@code propertyName}.
- *
- * @param host
- * @param propertyType the property type
- * @param propertyName the property name
- * @return a value model with this host and a reflective property with this type and name
- *
- * @see Property#of
- */
- public static <H, T> PropertyValueModel<H, T> of(H host, Class<T> propertyType,
- String propertyName) {
- return of(host, Property.of((Class<H>) host.getClass(), propertyType, propertyName));
- }
-
- private static Class getNullaryMethodReturnType(Class c, String name) {
- try {
- return c.getMethod(name).getReturnType();
- } catch (NoSuchMethodException e) {
- return null;
- }
- }
-
- private static Class getFieldType(Class c, String name) {
- try {
- return c.getField(name).getType();
- } catch (NoSuchFieldException e) {
- return null;
- }
- }
-
- private static String capitalize(String name) {
- if (name.isEmpty()) {
- return name;
- }
- return Character.toUpperCase(name.charAt(0)) + name.substring(1);
- }
-
- /**
- * Return a PropertyValueModel for this {@code host} and and {@code propertyName}.
- *
- * @param host the host
- * @param propertyName the property name
- * @return a value model with this host and a reflective property with this name
- */
- public static PropertyValueModel of(Object host, String propertyName) {
- Class clazz = host.getClass();
- String suffix = capitalize(propertyName);
- Class propertyType = getNullaryMethodReturnType(clazz, "get" + suffix);
- if (propertyType == null) {
- propertyType = getNullaryMethodReturnType(clazz, "is" + suffix);
- }
- if (propertyType == null) {
- propertyType = getFieldType(clazz, propertyName);
- }
- if (propertyType == null) {
- throw new NoSuchPropertyException(propertyName);
- }
- return of(host, propertyType, propertyName);
- }
-}
diff --git a/core/java/android/util/ValueModel.java b/core/java/android/util/ValueModel.java
deleted file mode 100755
index 4789682..0000000
--- a/core/java/android/util/ValueModel.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-/**
- * A ValueModel is an abstraction for a 'slot' or place in memory in which a value
- * may be stored and retrieved. A common implementation of ValueModel is a regular property of
- * an object, whose value may be retrieved by calling the appropriate <em>getter</em>
- * method and set by calling the corresponding <em>setter</em> method.
- *
- * @param <T> the value type
- *
- * @see PropertyValueModel
- */
-public abstract class ValueModel<T> {
- /**
- * The empty model should be used in place of {@code null} to indicate that a
- * model has not been set. The empty model has no value and does nothing when it is set.
- */
- public static final ValueModel EMPTY = new ValueModel() {
- @Override
- public Class getType() {
- return Object.class;
- }
-
- @Override
- public Object get() {
- return null;
- }
-
- @Override
- public void set(Object value) {
-
- }
- };
-
- protected ValueModel() {
- }
-
- /**
- * Returns the type of this property.
- *
- * @return the property type
- */
- public abstract Class<T> getType();
-
- /**
- * Returns the value of this property.
- *
- * @return the property value
- */
- public abstract T get();
-
- /**
- * Sets the value of this property.
- *
- * @param value the new value for this property
- */
- public abstract void set(T value);
-} \ No newline at end of file
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 351c5c3..b2988ed 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -228,7 +228,7 @@ public class FocusFinder {
if (focusable == focused || focusable == root) continue;
// get focus bounds of other view in same coordinate system
- focusable.getFocusRect(mOtherRect);
+ focusable.getFocusedRect(mOtherRect);
root.offsetDescendantRectToMyCoords(focusable, mOtherRect);
if (isBetterCandidate(direction, focusedRect, mOtherRect, mBestCandidateRect)) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 869cd00..032ff7b 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -150,7 +150,7 @@ class GLES20Canvas extends HardwareCanvas {
static native int nCreateTextureLayer(boolean opaque, int[] layerInfo);
static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
- static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
+ static native boolean nResizeLayer(int layerId, int width, int height, int[] layerInfo);
static native void nSetOpaqueLayer(int layerId, boolean isOpaque);
static native void nSetLayerPaint(int layerId, int nativePaint);
static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
index a77425a..fcfc8e1 100644
--- a/core/java/android/view/GLES20RenderLayer.java
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -54,8 +54,8 @@ class GLES20RenderLayer extends GLES20Layer {
}
@Override
- void resize(int width, int height) {
- if (!isValid() || width <= 0 || height <= 0) return;
+ boolean resize(int width, int height) {
+ if (!isValid() || width <= 0 || height <= 0) return false;
mWidth = width;
mHeight = height;
@@ -63,11 +63,17 @@ class GLES20RenderLayer extends GLES20Layer {
if (width != mLayerWidth || height != mLayerHeight) {
int[] layerInfo = new int[2];
- GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo);
-
- mLayerWidth = layerInfo[0];
- mLayerHeight = layerInfo[1];
+ if (GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo)) {
+ mLayerWidth = layerInfo[0];
+ mLayerHeight = layerInfo[1];
+ } else {
+ // Failure: not enough GPU resources for requested size
+ mLayer = 0;
+ mLayerWidth = 0;
+ mLayerHeight = 0;
+ }
}
+ return isValid();
}
@Override
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index e198ef6..b0ee2aa 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -48,7 +48,8 @@ class GLES20TextureLayer extends GLES20Layer {
}
@Override
- void resize(int width, int height) {
+ boolean resize(int width, int height) {
+ return isValid();
}
@Override
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index f031fe7..9a89fa5 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -153,8 +153,8 @@ public class Gravity
* container.
* @param layoutDirection The layout direction.
*
- * @see {@link View#LAYOUT_DIRECTION_LTR}
- * @see {@link View#LAYOUT_DIRECTION_RTL}
+ * @see View#LAYOUT_DIRECTION_LTR
+ * @see View#LAYOUT_DIRECTION_RTL
*/
public static void apply(int gravity, int w, int h, Rect container,
Rect outRect, int layoutDirection) {
@@ -290,8 +290,8 @@ public class Gravity
* container.
* @param layoutDirection The layout direction.
*
- * @see {@link View#LAYOUT_DIRECTION_LTR}
- * @see {@link View#LAYOUT_DIRECTION_RTL}
+ * @see View#LAYOUT_DIRECTION_LTR
+ * @see View#LAYOUT_DIRECTION_RTL
*/
public static void apply(int gravity, int w, int h, Rect container,
int xAdj, int yAdj, Rect outRect, int layoutDirection) {
@@ -370,8 +370,8 @@ public class Gravity
* modified if needed to fit in the display.
* @param layoutDirection The layout direction.
*
- * @see {@link View#LAYOUT_DIRECTION_LTR}
- * @see {@link View#LAYOUT_DIRECTION_RTL}
+ * @see View#LAYOUT_DIRECTION_LTR
+ * @see View#LAYOUT_DIRECTION_RTL
*/
public static void applyDisplay(int gravity, Rect display, Rect inoutObj, int layoutDirection) {
int absGravity = getAbsoluteGravity(gravity, layoutDirection);
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 6e763b2..d798e73 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -135,8 +135,9 @@ abstract class HardwareLayer {
*
* @param width The new desired minimum width for this layer
* @param height The new desired minimum height for this layer
+ * @return True if the resulting layer is valid, false otherwise
*/
- abstract void resize(int width, int height);
+ abstract boolean resize(int width, int height);
/**
* Returns a hardware canvas that can be used to render onto
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f906e24..ef5dc56 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -733,13 +733,17 @@ public abstract class HardwareRenderer {
*/
void checkEglErrors() {
if (isEnabled()) {
- int error = sEgl.eglGetError();
- if (error != EGL_SUCCESS) {
- // something bad has happened revert to
- // normal rendering.
- Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
- fallback(error != EGL11.EGL_CONTEXT_LOST);
- }
+ checkEglErrorsForced();
+ }
+ }
+
+ private void checkEglErrorsForced() {
+ int error = sEgl.eglGetError();
+ if (error != EGL_SUCCESS) {
+ // something bad has happened revert to
+ // normal rendering.
+ Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
+ fallback(error != EGL11.EGL_CONTEXT_LOST);
}
}
@@ -812,7 +816,9 @@ public abstract class HardwareRenderer {
throw new RuntimeException("eglInitialize failed " +
GLUtils.getEGLErrorString(sEgl.eglGetError()));
}
-
+
+ checkEglErrorsForced();
+
sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
// We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
@@ -1130,9 +1136,8 @@ public abstract class HardwareRenderer {
}
}
- int status = onPreDraw(dirty);
- int saveCount = canvas.save();
- callbacks.onHardwarePreDraw(canvas);
+ int saveCount = 0;
+ int status = DisplayList.STATUS_DONE;
try {
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
@@ -1158,6 +1163,10 @@ public abstract class HardwareRenderer {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
+ status = onPreDraw(dirty);
+ saveCount = canvas.save();
+ callbacks.onHardwarePreDraw(canvas);
+
if (mProfileEnabled) {
long now = System.nanoTime();
float total = (now - getDisplayListStartTime) * 0.000001f;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 03f9b72..87221e0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -48,9 +48,9 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.FloatProperty;
-import android.util.LocaleUtil;
import android.util.Log;
import android.util.Pool;
import android.util.Poolable;
@@ -83,12 +83,18 @@ import static java.lang.Math.max;
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
@@ -1503,7 +1509,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private SparseArray<Object> mKeyedTags;
/**
- * The next available accessiiblity id.
+ * The next available accessibility id.
*/
private static int sNextAccessibilityViewId;
@@ -1727,7 +1733,51 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static final int PFLAG_INVALIDATED = 0x80000000;
- /* Masks for mPrivateFlags2 */
+ /**
+ * Masks for mPrivateFlags2, as generated by dumpFlags():
+ *
+ * -------|-------|-------|-------|
+ * PFLAG2_TEXT_ALIGNMENT_FLAGS[0]
+ * PFLAG2_TEXT_DIRECTION_FLAGS[0]
+ * 1 PFLAG2_DRAG_CAN_ACCEPT
+ * 1 PFLAG2_DRAG_HOVERED
+ * 1 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT
+ * 11 PFLAG2_TEXT_DIRECTION_MASK_SHIFT
+ * 1 1 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT
+ * 11 PFLAG2_LAYOUT_DIRECTION_MASK
+ * 11 1 PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT
+ * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL
+ * 1 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT
+ * 1 1 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT
+ * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED
+ * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK
+ * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1]
+ * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2]
+ * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3]
+ * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4]
+ * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5]
+ * 111 PFLAG2_TEXT_DIRECTION_MASK
+ * 1 PFLAG2_TEXT_DIRECTION_RESOLVED
+ * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT
+ * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK
+ * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1]
+ * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2]
+ * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3]
+ * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4]
+ * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5]
+ * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6]
+ * 111 PFLAG2_TEXT_ALIGNMENT_MASK
+ * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED
+ * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT
+ * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK
+ * 11 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK
+ * 1 PFLAG2_HAS_TRANSIENT_STATE
+ * 1 PFLAG2_ACCESSIBILITY_FOCUSED
+ * 1 PFLAG2_ACCESSIBILITY_STATE_CHANGED
+ * 1 PFLAG2_VIEW_QUICK_REJECTED
+ * 1 PFLAG2_PADDING_RESOLVED
+ * -------|-------|-------|-------|
+ */
/**
* Indicates that this view has reported that it can accept the current drag's content.
@@ -1825,8 +1875,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide
*/
- static final int PFLAG2_HAS_TRANSIENT_STATE = 0x00000100;
-
+ static final int PFLAG2_HAS_TRANSIENT_STATE = 0x1 << 22;
/**
* Text direction is inherited thru {@link ViewGroup}
@@ -2053,7 +2102,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002;
/**
- * The default whether the view is important for accessiblity.
+ * The default whether the view is important for accessibility.
*/
static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@@ -2814,18 +2863,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int mUserPaddingEnd;
/**
- * Whether a left padding has been defined during layout inflation.
+ * Cache initial left padding.
*
* @hide
*/
- boolean mUserPaddingLeftDefined = false;
+ int mUserPaddingLeftInitial = UNDEFINED_PADDING;
/**
- * Whether a right padding has been defined during layout inflation.
+ * Cache initial right padding.
*
* @hide
*/
- boolean mUserPaddingRightDefined = false;
+ int mUserPaddingRightInitial = UNDEFINED_PADDING;
/**
* Default undefined padding
@@ -3125,7 +3174,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private boolean mSendingHoverAccessibilityEvents;
/**
- * Delegate for injecting accessiblity functionality.
+ * Delegate for injecting accessibility functionality.
*/
AccessibilityDelegate mAccessibilityDelegate;
@@ -3247,19 +3296,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
break;
case com.android.internal.R.styleable.View_padding:
padding = a.getDimensionPixelSize(attr, -1);
- mUserPaddingLeftDefined = true;
- mUserPaddingRightDefined = true;
+ mUserPaddingLeftInitial = padding;
+ mUserPaddingRightInitial = padding;
break;
case com.android.internal.R.styleable.View_paddingLeft:
leftPadding = a.getDimensionPixelSize(attr, -1);
- mUserPaddingLeftDefined = true;
+ mUserPaddingLeftInitial = leftPadding;
break;
case com.android.internal.R.styleable.View_paddingTop:
topPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingRight:
rightPadding = a.getDimensionPixelSize(attr, -1);
- mUserPaddingRightDefined = true;
+ mUserPaddingRightInitial = rightPadding;
break;
case com.android.internal.R.styleable.View_paddingBottom:
bottomPadding = a.getDimensionPixelSize(attr, -1);
@@ -3561,15 +3610,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
topPadding = padding;
rightPadding = padding;
bottomPadding = padding;
+ mUserPaddingLeftInitial = padding;
+ mUserPaddingRightInitial = padding;
}
// If the user specified the padding (either with android:padding or
// android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
// use the default padding or the padding from the background drawable
// (stored at this point in mPadding*)
- internalSetPadding(leftPadding >= 0 ? leftPadding : mPaddingLeft,
+ mUserPaddingLeftInitial = leftPadding >= 0 ? leftPadding : mPaddingLeft;
+ mUserPaddingRightInitial = rightPadding >= 0 ? rightPadding : mPaddingRight;
+ internalSetPadding(mUserPaddingLeftInitial,
topPadding >= 0 ? topPadding : mPaddingTop,
- rightPadding >= 0 ? rightPadding : mPaddingRight,
+ mUserPaddingRightInitial,
bottomPadding >= 0 ? bottomPadding : mPaddingBottom);
if (viewFlagMasks != 0) {
@@ -4475,7 +4528,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sends an accessibility event of the given type. If accessiiblity is
+ * Sends an accessibility event of the given type. If accessibility is
* not enabled this method has no effect. The default implementation calls
* {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first
* to populate information about the event source (this View), then calls
@@ -4894,7 +4947,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
info.setLongClickable(isLongClickable());
// TODO: These make sense only if we are in an AdapterView but all
- // views can be selected. Maybe from accessiiblity perspective
+ // views can be selected. Maybe from accessibility perspective
// we should report as selectable view in an AdapterView.
info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
@@ -5004,7 +5057,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sets a delegate for implementing accessibility support via compositon as
+ * Sets a delegate for implementing accessibility support via composition as
* opposed to inheritance. The delegate's primary use is for implementing
* backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
*
@@ -6680,7 +6733,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Returns whether the View is considered actionable from
* accessibility perspective. Such view are important for
- * accessiiblity.
+ * accessibility.
*
* @return True if the view is actionable for accessibility.
*
@@ -6692,7 +6745,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Returns whether the View has registered callbacks wich makes it
- * important for accessiiblity.
+ * important for accessibility.
*
* @return True if the view is actionable for accessibility.
*/
@@ -6731,7 +6784,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Reset the state indicating the this view has requested clients
- * interested in its accessiblity state to be notified.
+ * interested in its accessibility state to be notified.
*
* @hide
*/
@@ -8708,18 +8761,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
- /**
- * When searching for a view to focus this rectangle is used when considering if this view is
- * a good candidate for receiving focus.
- *
- * By default, the rectangle is the {@link #getDrawingRect}) of the view.
- *
- * @param r The rectangle to fill in, in this view's coordinates.
- */
- public void getFocusRect(Rect r) {
- getDrawingRect(r);
- }
-
/**
* Utility method to retrieve the inverse of the current mMatrix property.
* We cache the matrix to avoid recalculating it when transform properties
@@ -9698,7 +9739,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* When a view has focus and the user navigates away from it, the next view is searched for
* starting from the rectangle filled in by this method.
*
- * By default, the rectange is the {@link #getDrawingRect(android.graphics.Rect)})
+ * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)})
* of the view. However, if your view maintains some idea of internal selection,
* such as a cursor, or a selected row or column, you should override this method and
* fill in a more specific rectangle.
@@ -11552,10 +11593,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// left / right padding are used if defined. If they are not defined and start / end
// padding are defined (e.g. in Frameworks resources), then we use start / end and
// resolve them as left / right (layout direction is not taken into account).
- if (!mUserPaddingLeftDefined && mUserPaddingStart != UNDEFINED_PADDING) {
+ if (mUserPaddingLeftInitial == UNDEFINED_PADDING &&
+ mUserPaddingStart != UNDEFINED_PADDING) {
mUserPaddingLeft = mUserPaddingStart;
}
- if (!mUserPaddingRightDefined && mUserPaddingEnd != UNDEFINED_PADDING) {
+ if (mUserPaddingRightInitial == UNDEFINED_PADDING
+ && mUserPaddingEnd != UNDEFINED_PADDING) {
mUserPaddingRight = mUserPaddingEnd;
}
@@ -11569,6 +11612,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// left / right or right / left depending on the resolved layout direction.
// If start / end padding are not defined, use the left / right ones.
int resolvedLayoutDirection = getResolvedLayoutDirection();
+ // Set user padding to initial values ...
+ mUserPaddingLeft = (mUserPaddingLeftInitial == UNDEFINED_PADDING) ?
+ 0 : mUserPaddingLeftInitial;
+ mUserPaddingRight = (mUserPaddingRightInitial == UNDEFINED_PADDING) ?
+ 0 : mUserPaddingRightInitial;
+ // ... then resolve it.
switch (resolvedLayoutDirection) {
case LAYOUT_DIRECTION_RTL:
if (mUserPaddingStart != UNDEFINED_PADDING) {
@@ -11605,8 +11654,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param layoutDirection the direction of the layout
*
- * @see {@link #LAYOUT_DIRECTION_LTR}
- * @see {@link #LAYOUT_DIRECTION_RTL}
+ * @see #LAYOUT_DIRECTION_LTR
+ * @see #LAYOUT_DIRECTION_RTL
*/
public void onPaddingChanged(int layoutDirection) {
}
@@ -11655,7 +11704,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return true if the Locale uses an RTL script.
*/
protected static boolean isLayoutDirectionRtl(Locale locale) {
- return (LAYOUT_DIRECTION_RTL == LocaleUtil.getLayoutDirectionFromLocale(locale));
+ return (LAYOUT_DIRECTION_RTL == TextUtils.getLayoutDirectionFromLocale(locale));
}
/**
@@ -12213,8 +12262,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mLocalDirtyRect.set(0, 0, width, height);
} else {
if (mHardwareLayer.getWidth() != width || mHardwareLayer.getHeight() != height) {
- mHardwareLayer.resize(width, height);
- mLocalDirtyRect.set(0, 0, width, height);
+ if (mHardwareLayer.resize(width, height)) {
+ mLocalDirtyRect.set(0, 0, width, height);
+ }
}
// This should not be necessary but applications that change
@@ -12225,7 +12275,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
computeOpaqueFlags();
final boolean opaque = isOpaque();
- if (mHardwareLayer.isOpaque() != opaque) {
+ if (mHardwareLayer.isValid() && mHardwareLayer.isOpaque() != opaque) {
mHardwareLayer.setOpaque(opaque);
mLocalDirtyRect.set(0, 0, width, height);
}
@@ -14052,8 +14102,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param layoutDirection The resolved layout direction.
*
- * @see {@link #LAYOUT_DIRECTION_LTR}
- * @see {@link #LAYOUT_DIRECTION_RTL}
+ * @see #LAYOUT_DIRECTION_LTR
+ * @see #LAYOUT_DIRECTION_RTL
*/
public void onResolveDrawables(int layoutDirection) {
}
@@ -14333,10 +14383,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
switch (background.getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
+ mUserPaddingLeftInitial = padding.right;
+ mUserPaddingRightInitial = padding.left;
internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
break;
case LAYOUT_DIRECTION_LTR:
default:
+ mUserPaddingLeftInitial = padding.left;
+ mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
}
@@ -14433,6 +14487,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
+ mUserPaddingLeftInitial = left;
+ mUserPaddingRightInitial = right;
+
internalSetPadding(left, top, right, bottom);
}
@@ -14522,10 +14579,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
switch(getResolvedLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
+ mUserPaddingLeftInitial = end;
+ mUserPaddingRightInitial = start;
internalSetPadding(end, top, start, bottom);
break;
case LAYOUT_DIRECTION_LTR:
default:
+ mUserPaddingLeftInitial = start;
+ mUserPaddingRightInitial = end;
internalSetPadding(start, top, end, bottom);
}
}
@@ -18102,4 +18163,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return (view.mLabelForId == mLabeledId);
}
}
+
+ /**
+ * Dump all private flags in readable format, useful for documentation and
+ * sanity checking.
+ */
+ private static void dumpFlags() {
+ final HashMap<String, String> found = Maps.newHashMap();
+ try {
+ for (Field field : View.class.getDeclaredFields()) {
+ final int modifiers = field.getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+ if (field.getType().equals(int.class)) {
+ final int value = field.getInt(null);
+ dumpFlag(found, field.getName(), value);
+ } else if (field.getType().equals(int[].class)) {
+ final int[] values = (int[]) field.get(null);
+ for (int i = 0; i < values.length; i++) {
+ dumpFlag(found, field.getName() + "[" + i + "]", values[i]);
+ }
+ }
+ }
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+
+ final ArrayList<String> keys = Lists.newArrayList();
+ keys.addAll(found.keySet());
+ Collections.sort(keys);
+ for (String key : keys) {
+ Log.d(VIEW_LOG_TAG, found.get(key));
+ }
+ }
+
+ private static void dumpFlag(HashMap<String, String> found, String name, int value) {
+ // Sort flags by prefix, then by bits, always keeping unique keys
+ final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' ');
+ final int prefix = name.indexOf('_');
+ final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name;
+ final String output = bits + " " + name;
+ found.put(key, output);
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d6a0203..27fd374 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1402,6 +1402,7 @@ public final class ViewRootImpl implements ViewParent,
mResizeBuffer.getHeight() != mHeight) {
mResizeBuffer.resize(mWidth, mHeight);
}
+ // TODO: should handle create/resize failure
layerCanvas = mResizeBuffer.start(hwRendererCanvas);
layerCanvas.setViewport(mWidth, mHeight);
layerCanvas.onPreDraw(null);
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index c93da06..d6f63a7 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -832,7 +832,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
sConfirmSafeVolumeDialog.dismiss();
}
sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
- .setTitle(android.R.string.dialog_alert_title)
.setMessage(com.android.internal.R.string.safe_media_volume_warning)
.setPositiveButton(com.android.internal.R.string.yes,
new DialogInterface.OnClickListener() {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a242895..06974d3 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -89,6 +89,13 @@ public abstract class Window {
* If overlay is enabled, the action mode UI will be allowed to cover existing window content.
*/
public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
+
+ /**
+ * Max value used as a feature ID
+ * @hide
+ */
+ public static final int FEATURE_MAX = FEATURE_ACTION_MODE_OVERLAY;
+
/** Flag for setting the progress bar's visibility to VISIBLE */
public static final int PROGRESS_VISIBILITY_ON = -1;
/** Flag for setting the progress bar's visibility to GONE */
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 75554da..82f07c7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1111,7 +1111,15 @@ public interface WindowManagerPolicy {
* @param attrs The window's LayoutParams.
* @return Whether magnification can be applied.
*/
- public boolean canMagnifyWindow(WindowManager.LayoutParams attrs);
+ public boolean canMagnifyWindowLw(WindowManager.LayoutParams attrs);
+
+ /**
+ * Called when the current user changes. Guaranteed to be called before the broadcast
+ * of the new user id is made to all listeners.
+ *
+ * @param newUserId The id of the incoming user.
+ */
+ public void setCurrentUserLw(int newUserId);
/**
* Print the WindowManagerPolicy's state into the given stream.
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index d9aeb70..e6eaa14 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -89,7 +89,6 @@ final class JWebCoreJavaBridge extends Handler {
private void fireSharedTimer() {
// clear the flag so that sharedTimerFired() can set a new timer
mHasInstantTimer = false;
- removeMessages(TIMER_MESSAGE);
sharedTimerFired();
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index da0cc5f..33fe834 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2198,20 +2198,12 @@ public final class WebViewCore {
mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
}
m_skipDrawFlag = false;
- m_skipDrawFlagLock.notify();
}
}
private void webkitDraw() {
synchronized (m_skipDrawFlagLock) {
if (m_skipDrawFlag) {
- try {
- // Aggressively throttle webkit to give the UI more CPU
- // to catch up with
- m_skipDrawFlagLock.wait(50);
- } catch (InterruptedException e) {}
- }
- if (m_skipDrawFlag) {
m_drawWasSkipped = true;
return;
}
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index f79ec42..27d15f6 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -24,8 +24,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.graphics.drawable.Drawable;
@@ -272,7 +270,7 @@ public class AppSecurityPermissions {
setPermissions(mPermsList);
}
- public AppSecurityPermissions(Context context, PackageParser.Package pkg) {
+ public AppSecurityPermissions(Context context, PackageInfo info) {
mContext = context;
mPm = mContext.getPackageManager();
loadResources();
@@ -280,14 +278,11 @@ public class AppSecurityPermissions {
mPermGroupComparator = new PermissionGroupInfoComparator();
mPermsList = new ArrayList<MyPermissionInfo>();
Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>();
- if(pkg == null) {
+ if(info == null) {
return;
}
// Convert to a PackageInfo
- PackageInfo info = PackageParser.generatePackageInfo(pkg, null,
- PackageManager.GET_PERMISSIONS, 0, 0, null,
- new PackageUserState());
PackageInfo installedPkgInfo = null;
// Get requested permissions
if (info.requestedPermissions != null) {
@@ -299,13 +294,13 @@ public class AppSecurityPermissions {
extractPerms(info, permSet, installedPkgInfo);
}
// Get permissions related to shared user if any
- if (pkg.mSharedUserId != null) {
+ if (info.sharedUserId != null) {
int sharedUid;
try {
- sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId);
+ sharedUid = mPm.getUidForSharedUser(info.sharedUserId);
getAllUsedPermissions(sharedUid, permSet);
} catch (NameNotFoundException e) {
- Log.w(TAG, "Could'nt retrieve shared user id for:"+pkg.packageName);
+ Log.w(TAG, "Could'nt retrieve shared user id for:"+info.packageName);
}
}
// Retrieve list of permissions
diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java
index 41ab5f2..f1804f8 100644
--- a/core/java/android/widget/CheckBox.java
+++ b/core/java/android/widget/CheckBox.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.util.ValueModel;
/**
@@ -56,9 +55,7 @@ import android.util.ValueModel;
* {@link android.R.styleable#View View Attributes}
* </p>
*/
-public class CheckBox extends CompoundButton implements ValueEditor<Boolean> {
- private ValueModel<Boolean> mValueModel = ValueModel.EMPTY;
-
+public class CheckBox extends CompoundButton {
public CheckBox(Context context) {
this(context, null);
}
@@ -82,22 +79,4 @@ public class CheckBox extends CompoundButton implements ValueEditor<Boolean> {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(CheckBox.class.getName());
}
-
- @Override
- public ValueModel<Boolean> getValueModel() {
- return mValueModel;
- }
-
- @Override
- public void setValueModel(ValueModel<Boolean> valueModel) {
- mValueModel = valueModel;
- setChecked(mValueModel.get());
- }
-
- @Override
- public boolean performClick() {
- boolean handled = super.performClick();
- mValueModel.set(isChecked());
- return handled;
- }
}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index ec81214..57e51c2 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.graphics.Rect;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
@@ -25,7 +24,6 @@ import android.text.TextUtils;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.MovementMethod;
import android.util.AttributeSet;
-import android.util.ValueModel;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -49,9 +47,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
* {@link android.R.styleable#TextView TextView Attributes},
* {@link android.R.styleable#View View Attributes}
*/
-public class EditText extends TextView implements ValueEditor<CharSequence> {
- private ValueModel<CharSequence> mValueModel = ValueModel.EMPTY;
-
+public class EditText extends TextView {
public EditText(Context context) {
this(context, null);
}
@@ -132,21 +128,4 @@ public class EditText extends TextView implements ValueEditor<CharSequence> {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(EditText.class.getName());
}
-
- @Override
- public ValueModel<CharSequence> getValueModel() {
- return mValueModel;
- }
-
- @Override
- public void setValueModel(ValueModel<CharSequence> valueModel) {
- mValueModel = valueModel;
- setText(mValueModel.get());
- }
-
- @Override
- void sendAfterTextChanged(Editable text) {
- super.sendAfterTextChanged(text);
- mValueModel.set(text);
- }
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 7f9dab9..237275a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1801,13 +1801,13 @@ public class Editor {
mTextView.deleteText_internal(dragSourceStart, dragSourceEnd);
// Make sure we do not leave two adjacent spaces.
- CharSequence t = mTextView.getTransformedText(dragSourceStart - 1, dragSourceStart + 1);
- if ( (dragSourceStart == 0 || Character.isSpaceChar(t.charAt(0))) &&
- (dragSourceStart == mTextView.getText().length() ||
- Character.isSpaceChar(t.charAt(1))) ) {
- final int pos = dragSourceStart == mTextView.getText().length() ?
- dragSourceStart - 1 : dragSourceStart;
- mTextView.deleteText_internal(pos, pos + 1);
+ final int prevCharIdx = Math.max(0, dragSourceStart - 1);
+ final int nextCharIdx = Math.min(mTextView.getText().length(), dragSourceStart + 1);
+ if (nextCharIdx > prevCharIdx + 1) {
+ CharSequence t = mTextView.getTransformedText(prevCharIdx, nextCharIdx);
+ if (Character.isSpaceChar(t.charAt(0)) && Character.isSpaceChar(t.charAt(1))) {
+ mTextView.deleteText_internal(prevCharIdx, prevCharIdx + 1);
+ }
}
}
}
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3baf5a9..1c81d11 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -21,8 +21,8 @@ import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.LocaleUtil;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -200,7 +200,7 @@ public class ListPopupWindow {
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
// Set the default layout direction to match the default locale one
final Locale locale = mContext.getResources().getConfiguration().locale;
- mLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
+ mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
}
/**
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index a6486a8..2737f94 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -18,7 +18,6 @@ package android.widget;
import android.content.Context;
import android.util.AttributeSet;
-import android.util.ValueModel;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -34,7 +33,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
*
* @attr ref android.R.styleable#SeekBar_thumb
*/
-public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> {
+public class SeekBar extends AbsSeekBar {
/**
* A callback that notifies clients when the progress level has been
@@ -70,9 +69,8 @@ public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> {
void onStopTrackingTouch(SeekBar seekBar);
}
- private ValueModel<Integer> mValueModel = ValueModel.EMPTY;
private OnSeekBarChangeListener mOnSeekBarChangeListener;
-
+
public SeekBar(Context context) {
this(context, null);
}
@@ -91,23 +89,9 @@ public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
- if (fromUser) {
- mValueModel.set(getProgress());
- }
}
}
- @Override
- public ValueModel<Integer> getValueModel() {
- return mValueModel;
- }
-
- @Override
- public void setValueModel(ValueModel<Integer> valueModel) {
- mValueModel = valueModel;
- setProgress(mValueModel.get());
- }
-
/**
* Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
* provides notifications of when the user starts and stops a touch gesture within the SeekBar.
diff --git a/core/java/android/widget/ValueEditor.java b/core/java/android/widget/ValueEditor.java
deleted file mode 100755
index 2b91abf..0000000
--- a/core/java/android/widget/ValueEditor.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import android.util.ValueModel;
-
-/**
- * An interface for editors of simple values. Classes implementing this interface are normally
- * UI controls (subclasses of {@link android.view.View View}) that can provide a suitable
- * user interface to display and edit values of the specified type. This interface is
- * intended to describe editors for simple types, like {@code boolean}, {@code int} or
- * {@code String}, where the values themselves are immutable.
- * <p>
- * For example, {@link android.widget.CheckBox CheckBox} implements
- * this interface for the Boolean type as it is capable of providing an appropriate
- * mechanism for displaying and changing the value of a Boolean property.
- *
- * @param <T> the value type that this editor supports
- */
-public interface ValueEditor<T> {
- /**
- * Return the last value model that was set. If no value model has been set, the editor
- * should return the value {@link android.util.ValueModel#EMPTY}.
- *
- * @return the value model
- */
- public ValueModel<T> getValueModel();
-
- /**
- * Sets the value model for this editor. When the value model is set, the editor should
- * retrieve the value from the value model, using {@link android.util.ValueModel#get()},
- * and set its internal state accordingly. Likewise, when the editor's internal state changes
- * it should update the value model by calling {@link android.util.ValueModel#set(T)}
- * with the appropriate value.
- *
- * @param valueModel the new value model for this editor.
- */
- public void setValueModel(ValueModel<T> valueModel);
-}
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index bcf0ea4..43a02cf 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -347,6 +347,18 @@ public class AlertController {
}
}
+ /**
+ * @param attrId the attributeId of the theme-specific drawable
+ * to resolve the resourceId for.
+ *
+ * @return resId the resourceId of the theme-specific drawable
+ */
+ public int getIconAttributeResId(int attrId) {
+ TypedValue out = new TypedValue();
+ mContext.getTheme().resolveAttribute(attrId, out, true);
+ return out.resourceId;
+ }
+
public void setInverseBackgroundForced(boolean forceInverseBackground) {
mForceInverseBackground = forceInverseBackground;
}
@@ -740,6 +752,7 @@ public class AlertController {
public int mIconId = 0;
public Drawable mIcon;
+ public int mIconAttrId = 0;
public CharSequence mTitle;
public View mCustomTitleView;
public CharSequence mMessage;
@@ -807,6 +820,9 @@ public class AlertController {
if (mIconId >= 0) {
dialog.setIcon(mIconId);
}
+ if (mIconAttrId > 0) {
+ dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
+ }
}
if (mMessage != null) {
dialog.setMessage(mMessage);
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index dc4ee3a..34ade74 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -400,6 +400,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
int nonOverflowCount = 0;
int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
boolean hasOverflow = false;
+ final boolean isLayoutRtl = isLayoutRtl();
for (int i = 0; i < childCount; i++) {
final View v = getChildAt(i);
if (v.getVisibility() == GONE) {
@@ -414,8 +415,15 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
int height = v.getMeasuredHeight();
- int r = getWidth() - getPaddingRight() - p.rightMargin;
- int l = r - overflowWidth;
+ int r;
+ int l;
+ if (isLayoutRtl) {
+ l = getPaddingLeft() + p.leftMargin;
+ r = l + overflowWidth;
+ } else {
+ r = getWidth() - getPaddingRight() - p.rightMargin;
+ l = r - overflowWidth;
+ }
int t = midVertical - (height / 2);
int b = t + height;
v.layout(l, t, r, b);
@@ -448,20 +456,38 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
- int startLeft = getPaddingLeft();
- for (int i = 0; i < childCount; i++) {
- final View v = getChildAt(i);
- final LayoutParams lp = (LayoutParams) v.getLayoutParams();
- if (v.getVisibility() == GONE || lp.isOverflowButton) {
- continue;
+ if (isLayoutRtl) {
+ int startRight = getWidth() - getPaddingRight();
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ if (v.getVisibility() == GONE || lp.isOverflowButton) {
+ continue;
+ }
+
+ startRight -= lp.rightMargin;
+ int width = v.getMeasuredWidth();
+ int height = v.getMeasuredHeight();
+ int t = midVertical - height / 2;
+ v.layout(startRight - width, t, startRight, t + height);
+ startRight -= width + lp.leftMargin + spacerSize;
}
+ } else {
+ int startLeft = getPaddingLeft();
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ if (v.getVisibility() == GONE || lp.isOverflowButton) {
+ continue;
+ }
- startLeft += lp.leftMargin;
- int width = v.getMeasuredWidth();
- int height = v.getMeasuredHeight();
- int t = midVertical - height / 2;
- v.layout(startLeft, t, startLeft + width, t + height);
- startLeft += width + lp.rightMargin + spacerSize;
+ startLeft += lp.leftMargin;
+ int width = v.getMeasuredWidth();
+ int height = v.getMeasuredHeight();
+ int t = midVertical - height / 2;
+ v.layout(startLeft, t, startLeft + width, t + height);
+ startLeft += width + lp.rightMargin + spacerSize;
+ }
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 0710d96..8756950 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -22,14 +22,11 @@ import com.google.android.collect.Lists;
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.FileObserver;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -45,16 +42,10 @@ import android.util.Log;
import android.view.View;
import android.widget.Button;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Utilities for the lock pattern and its settings.
@@ -134,7 +125,7 @@ public class LockPatternUtils {
private final ContentResolver mContentResolver;
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
- private int mCurrentUserId = 0;
+ private int mCurrentUserId = UserHandle.USER_NULL;
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
@@ -165,7 +156,7 @@ public class LockPatternUtils {
}
public int getRequestedMinimumPasswordLength() {
- return getDevicePolicyManager().getPasswordMinimumLength(null);
+ return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId());
}
/**
@@ -173,47 +164,54 @@ public class LockPatternUtils {
* MODE_PATTERN which allows the user to choose anything.
*/
public int getRequestedPasswordQuality() {
- return getDevicePolicyManager().getPasswordQuality(null);
+ return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId());
}
public int getRequestedPasswordHistoryLength() {
- return getDevicePolicyManager().getPasswordHistoryLength(null);
+ return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
}
public int getRequestedPasswordMinimumLetters() {
- return getDevicePolicyManager().getPasswordMinimumLetters(null);
+ return getDevicePolicyManager().getPasswordMinimumLetters(null,
+ getCurrentOrCallingUserId());
}
public int getRequestedPasswordMinimumUpperCase() {
- return getDevicePolicyManager().getPasswordMinimumUpperCase(null);
+ return getDevicePolicyManager().getPasswordMinimumUpperCase(null,
+ getCurrentOrCallingUserId());
}
public int getRequestedPasswordMinimumLowerCase() {
- return getDevicePolicyManager().getPasswordMinimumLowerCase(null);
+ return getDevicePolicyManager().getPasswordMinimumLowerCase(null,
+ getCurrentOrCallingUserId());
}
public int getRequestedPasswordMinimumNumeric() {
- return getDevicePolicyManager().getPasswordMinimumNumeric(null);
+ return getDevicePolicyManager().getPasswordMinimumNumeric(null,
+ getCurrentOrCallingUserId());
}
public int getRequestedPasswordMinimumSymbols() {
- return getDevicePolicyManager().getPasswordMinimumSymbols(null);
+ return getDevicePolicyManager().getPasswordMinimumSymbols(null,
+ getCurrentOrCallingUserId());
}
public int getRequestedPasswordMinimumNonLetter() {
- return getDevicePolicyManager().getPasswordMinimumNonLetter(null);
+ return getDevicePolicyManager().getPasswordMinimumNonLetter(null,
+ getCurrentOrCallingUserId());
}
+
/**
* Returns the actual password mode, as set by keyguard after updating the password.
*
* @return
*/
public void reportFailedPasswordAttempt() {
- getDevicePolicyManager().reportFailedPasswordAttempt();
+ getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
}
public void reportSuccessfulPasswordAttempt() {
- getDevicePolicyManager().reportSuccessfulPasswordAttempt();
+ getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
}
public void setCurrentUser(int userId) {
@@ -226,10 +224,14 @@ public class LockPatternUtils {
public int getCurrentUser() {
if (Process.myUid() == Process.SYSTEM_UID) {
+ if (mCurrentUserId != UserHandle.USER_NULL) {
+ // Someone is regularly updating using setCurrentUser() use that value.
+ return mCurrentUserId;
+ }
try {
return ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException re) {
- return mCurrentUserId;
+ return UserHandle.USER_OWNER;
}
} else {
throw new SecurityException("Only the system process can get the current user");
@@ -249,7 +251,9 @@ public class LockPatternUtils {
private int getCurrentOrCallingUserId() {
int callingUid = Binder.getCallingUid();
if (callingUid == android.os.Process.SYSTEM_UID) {
- return mCurrentUserId;
+ // TODO: This is a little inefficient. See if all users of this are able to
+ // handle USER_CURRENT and pass that instead.
+ return getCurrentUser();
} else {
return UserHandle.getUserId(callingUid);
}
@@ -481,21 +485,21 @@ public class LockPatternUtils {
deleteGallery();
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
- pattern.size(), 0, 0, 0, 0, 0, 0);
+ pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
} else {
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
setLong(PASSWORD_TYPE_ALTERNATE_KEY,
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
finishBiometricWeak();
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
- 0, 0, 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
}
} else {
if (keyStore.isEmpty()) {
keyStore.reset();
}
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
}
} catch (RemoteException re) {
Log.e(TAG, "Couldn't save lock pattern " + re);
@@ -532,7 +536,8 @@ public class LockPatternUtils {
/** Update the encryption password if it is enabled **/
private void updateEncryptionPassword(String password) {
DevicePolicyManager dpm = getDevicePolicyManager();
- if (dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
+ if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
+ != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
return;
}
@@ -558,7 +563,7 @@ public class LockPatternUtils {
* @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
*/
public void saveLockPassword(String password, int quality) {
- this.saveLockPassword(password, quality, false);
+ this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
}
/**
@@ -570,23 +575,42 @@ public class LockPatternUtils {
* @param isFallback Specifies if this is a fallback to biometric weak
*/
public void saveLockPassword(String password, int quality, boolean isFallback) {
+ saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
+ }
+
+ /**
+ * Save a lock password. Does not ensure that the password is as good
+ * as the requested mode, but will adjust the mode to be as good as the
+ * pattern.
+ * @param password The password to save
+ * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+ * @param isFallback Specifies if this is a fallback to biometric weak
+ * @param userHandle The userId of the user to change the password for
+ */
+ public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
// Compute the hash
final byte[] hash = passwordToHash(password);
try {
- getLockSettings().setLockPassword(hash, getCurrentOrCallingUserId());
+ if (Process.myUid() != Process.SYSTEM_UID && userHandle != UserHandle.myUserId()) {
+ throw new SecurityException(
+ "Only the system process can save lock password for another user");
+ }
+ getLockSettings().setLockPassword(hash, userHandle);
DevicePolicyManager dpm = getDevicePolicyManager();
KeyStore keyStore = KeyStore.getInstance();
if (password != null) {
- // Update the encryption password.
- updateEncryptionPassword(password);
+ if (userHandle == UserHandle.USER_OWNER) {
+ // Update the encryption password.
+ updateEncryptionPassword(password);
- // Update the keystore password
- keyStore.password(password);
+ // Update the keystore password
+ keyStore.password(password);
+ }
int computedQuality = computePasswordQuality(password);
if (!isFallback) {
deleteGallery();
- setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
+ setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int letters = 0;
int uppercase = 0;
@@ -612,25 +636,27 @@ public class LockPatternUtils {
}
dpm.setActivePasswordState(Math.max(quality, computedQuality),
password.length(), letters, uppercase, lowercase,
- numbers, symbols, nonletter);
+ numbers, symbols, nonletter, userHandle);
} else {
// The password is not anything.
dpm.setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- 0, 0, 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0, 0, userHandle);
}
} else {
// Case where it's a fallback for biometric weak
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
- setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality));
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
+ userHandle);
+ setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
+ userHandle);
finishBiometricWeak();
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
- 0, 0, 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0, 0, userHandle);
}
// Add the password to the password history. We assume all
// password
// hashes have the same length for simplicity of implementation.
- String passwordHistory = getString(PASSWORD_HISTORY_KEY);
+ String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
if (passwordHistory == null) {
passwordHistory = new String();
}
@@ -645,7 +671,7 @@ public class LockPatternUtils {
* passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
.length()));
}
- setString(PASSWORD_HISTORY_KEY, passwordHistory);
+ setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
} else {
// Conditionally reset the keystore if empty. If
// non-empty, we are just switching key guard type
@@ -653,7 +679,8 @@ public class LockPatternUtils {
keyStore.reset();
}
dpm.setActivePasswordState(
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0);
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
+ userHandle);
}
} catch (RemoteException re) {
// Cant do much
@@ -849,7 +876,7 @@ public class LockPatternUtils {
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
return false;
}
- if (getDevicePolicyManager().getCameraDisabled(null)) {
+ if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
return false;
}
@@ -1027,6 +1054,10 @@ public class LockPatternUtils {
}
private void setLong(String secureSettingKey, long value) {
+ setLong(secureSettingKey, value, getCurrentOrCallingUserId());
+ }
+
+ private void setLong(String secureSettingKey, long value, int userHandle) {
try {
getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId());
} catch (RemoteException re) {
@@ -1036,17 +1067,20 @@ public class LockPatternUtils {
}
private String getString(String secureSettingKey) {
+ return getString(secureSettingKey, getCurrentOrCallingUserId());
+ }
+
+ private String getString(String secureSettingKey, int userHandle) {
try {
- return getLockSettings().getString(secureSettingKey, null,
- getCurrentOrCallingUserId());
+ return getLockSettings().getString(secureSettingKey, null, userHandle);
} catch (RemoteException re) {
return null;
}
}
- private void setString(String secureSettingKey, String value) {
+ private void setString(String secureSettingKey, String value, int userHandle) {
try {
- getLockSettings().setString(secureSettingKey, value, getCurrentOrCallingUserId());
+ getLockSettings().setString(secureSettingKey, value, userHandle);
} catch (RemoteException re) {
// What can we do?
Log.e(TAG, "Couldn't write string " + secureSettingKey + re);
@@ -1078,8 +1112,13 @@ public class LockPatternUtils {
* {@link TelephonyManager#CALL_STATE_RINGING}
* {@link TelephonyManager#CALL_STATE_OFFHOOK}
* @param shown indicates whether the given screen wants the emergency button to show at all
+ * @param button
+ * @param phoneState
+ * @param shown shown if true; hidden if false
+ * @param upperCase if true, converts button label string to upper case
*/
- public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
+ public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown,
+ boolean upperCase, boolean showIcon) {
if (isEmergencyCallCapable() && shown) {
button.setVisibility(View.VISIBLE);
} else {
@@ -1091,14 +1130,30 @@ public class LockPatternUtils {
if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) {
// show "return to call" text and show phone icon
textId = R.string.lockscreen_return_to_call;
- int phoneCallIcon = R.drawable.stat_sys_phone_call;
+ int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
} else {
textId = R.string.lockscreen_emergency_call;
- int emergencyIcon = R.drawable.ic_emergency;
+ int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
}
- button.setText(textId);
+ if (upperCase) {
+ CharSequence original = mContext.getResources().getText(textId);
+ String upper = original != null ? original.toString().toUpperCase() : null;
+ button.setText(upper);
+ } else {
+ button.setText(textId);
+ }
+ }
+
+ /**
+ * @deprecated
+ * @param button
+ * @param phoneState
+ * @param shown
+ */
+ public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
+ updateEmergencyCallButtonState(button, phoneState, shown, false, true);
}
/**