diff options
Diffstat (limited to 'core/java/android')
46 files changed, 793 insertions, 739 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index eae3b1f..773f73c 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(); @@ -2152,6 +2160,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(); 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..2fb17b6 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; @@ -496,7 +492,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; 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..0f6488a 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,49 @@ 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"); } + + 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 +193,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 +233,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 +264,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 +273,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 +606,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 +636,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 +705,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 +732,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 +741,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 +775,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 +826,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..e8507bc 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2376,6 +2376,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/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/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/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..44b0b62 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,6 +42,7 @@ 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() { 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..68ce72f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5614,6 +5614,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/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 'M' 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/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..446a51e 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 diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 03f9b72..c374ca6 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; @@ -8708,18 +8708,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 +9686,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. @@ -11605,8 +11593,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 +11643,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 +12201,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 +12214,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 +14041,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) { } 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/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); -} |
