diff options
Diffstat (limited to 'core/java')
48 files changed, 928 insertions, 488 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 9caf84f..fc569e0 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -647,16 +647,17 @@ public class AccountManagerService if (response == null) throw new IllegalArgumentException("response is null"); if (account == null) throw new IllegalArgumentException("account is null"); checkManageAccountsPermission(); + UserHandle user = Binder.getCallingUserHandle(); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); - cancelNotification(getSigninRequiredNotificationId(accounts, account)); + cancelNotification(getSigninRequiredNotificationId(accounts, account), user); synchronized(accounts.credentialsPermissionNotificationIds) { for (Pair<Pair<Account, String>, Integer> pair: accounts.credentialsPermissionNotificationIds.keySet()) { if (account.equals(pair.first.first)) { int id = accounts.credentialsPermissionNotificationIds.get(pair); - cancelNotification(id); + cancelNotification(id, user); } } } @@ -789,7 +790,8 @@ public class AccountManagerService if (account == null || type == null) { return false; } - cancelNotification(getSigninRequiredNotificationId(accounts, account)); + cancelNotification(getSigninRequiredNotificationId(accounts, account), + new UserHandle(accounts.userId)); synchronized (accounts.cacheLock) { final SQLiteDatabase db = accounts.openHelper.getWritableDatabase(); db.beginTransaction(); @@ -1173,11 +1175,12 @@ public class AccountManagerService title = titleAndSubtitle.substring(0, index); subtitle = titleAndSubtitle.substring(index + 1); } + UserHandle user = new UserHandle(userId); n.setLatestEventInfo(mContext, title, subtitle, PendingIntent.getActivityAsUser(mContext, 0, intent, - PendingIntent.FLAG_CANCEL_CURRENT, - null, new UserHandle(userId))); - installNotification(getCredentialPermissionNotificationId(account, authTokenType, uid), n); + PendingIntent.FLAG_CANCEL_CURRENT, null, user)); + installNotification(getCredentialPermissionNotificationId( + account, authTokenType, uid), n, user); } String getAccountLabel(String accountType) { @@ -1763,7 +1766,8 @@ public class AccountManagerService String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE); if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { Account account = new Account(accountName, accountType); - cancelNotification(getSigninRequiredNotificationId(mAccounts, account)); + cancelNotification(getSigninRequiredNotificationId(mAccounts, account), + new UserHandle(mAccounts.userId)); } } IAccountManagerResponse response; @@ -2101,30 +2105,32 @@ public class AccountManagerService intent.addCategory(String.valueOf(notificationId)); Notification n = new Notification(android.R.drawable.stat_sys_warning, null, 0 /* when */); + UserHandle user = new UserHandle(userId); final String notificationTitleFormat = mContext.getText(R.string.notification_title).toString(); n.setLatestEventInfo(mContext, String.format(notificationTitleFormat, account.name), message, PendingIntent.getActivityAsUser( mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, - null, new UserHandle(userId))); - installNotification(notificationId, n); + null, user)); + installNotification(notificationId, n, user); } } finally { restoreCallingIdentity(identityToken); } } - protected void installNotification(final int notificationId, final Notification n) { + protected void installNotification(final int notificationId, final Notification n, + UserHandle user) { ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)) - .notify(notificationId, n); + .notifyAsUser(null, notificationId, n, user); } - protected void cancelNotification(int id) { + protected void cancelNotification(int id, UserHandle user) { long identityToken = clearCallingIdentity(); try { ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)) - .cancel(id); + .cancelAsUser(null, id, user); } finally { restoreCallingIdentity(identityToken); } @@ -2289,7 +2295,8 @@ public class AccountManagerService } finally { db.endTransaction(); } - cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid)); + cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid), + new UserHandle(accounts.userId)); } } @@ -2323,7 +2330,8 @@ public class AccountManagerService } finally { db.endTransaction(); } - cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid)); + cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid), + new UserHandle(accounts.userId)); } } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b0df660..c3f57e8 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -632,8 +632,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); String name = data.readString(); + int userId = data.readInt(); boolean stable = data.readInt() != 0; - ContentProviderHolder cph = getContentProvider(app, name, stable); + ContentProviderHolder cph = getContentProvider(app, name, userId, stable); reply.writeNoException(); if (cph != null) { reply.writeInt(1); @@ -647,8 +648,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String name = data.readString(); + int userId = data.readInt(); IBinder token = data.readStrongBinder(); - ContentProviderHolder cph = getContentProviderExternal(name, token); + ContentProviderHolder cph = getContentProviderExternal(name, userId, token); reply.writeNoException(); if (cph != null) { reply.writeInt(1); @@ -2495,12 +2497,13 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } public ContentProviderHolder getContentProvider(IApplicationThread caller, - String name, boolean stable) throws RemoteException { + String name, int userId, boolean stable) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeString(name); + data.writeInt(userId); data.writeInt(stable ? 1 : 0); mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0); reply.readException(); @@ -2513,13 +2516,13 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return cph; } - public ContentProviderHolder getContentProviderExternal(String name, IBinder token) - throws RemoteException - { + public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeString(name); + data.writeInt(userId); data.writeStrongBinder(token); mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0); reply.readException(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 67ecf5b..aa8ef21 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -89,6 +89,7 @@ import android.renderscript.RenderScript; import com.android.internal.os.BinderInternal; import com.android.internal.os.RuntimeInit; import com.android.internal.os.SamplingProfilerIntegration; +import com.android.internal.util.Objects; import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; @@ -214,9 +215,33 @@ public final class ActivityThread { = new ArrayList<ActivityClientRecord>(); Configuration mPendingConfiguration = null; + private static final class ProviderKey { + final String authority; + final int userId; + + public ProviderKey(String authority, int userId) { + this.authority = authority; + this.userId = userId; + } + + @Override + public boolean equals(Object o) { + if (o instanceof ProviderKey) { + final ProviderKey other = (ProviderKey) o; + return Objects.equal(authority, other.authority) && userId == other.userId; + } + return false; + } + + @Override + public int hashCode() { + return ((authority != null) ? authority.hashCode() : 0) ^ userId; + } + } + // The lock of mProviderMap protects the following variables. - final HashMap<String, ProviderClientRecord> mProviderMap - = new HashMap<String, ProviderClientRecord>(); + final HashMap<ProviderKey, ProviderClientRecord> mProviderMap + = new HashMap<ProviderKey, ProviderClientRecord>(); final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap = new HashMap<IBinder, ProviderRefCount>(); final HashMap<IBinder, ProviderClientRecord> mLocalProviders @@ -4360,8 +4385,9 @@ public final class ActivityThread { } } - public final IContentProvider acquireProvider(Context c, String name, boolean stable) { - IContentProvider provider = acquireExistingProvider(c, name, stable); + public final IContentProvider acquireProvider( + Context c, String auth, int userId, boolean stable) { + final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } @@ -4375,11 +4401,11 @@ public final class ActivityThread { IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( - getApplicationThread(), name, stable); + getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { } if (holder == null) { - Slog.e(TAG, "Failed to find provider info for " + name); + Slog.e(TAG, "Failed to find provider info for " + auth); return null; } @@ -4456,10 +4482,11 @@ public final class ActivityThread { } } - public final IContentProvider acquireExistingProvider(Context c, String name, - boolean stable) { + public final IContentProvider acquireExistingProvider( + Context c, String auth, int userId, boolean stable) { synchronized (mProviderMap) { - ProviderClientRecord pr = mProviderMap.get(name); + final ProviderKey key = new ProviderKey(auth, userId); + final ProviderClientRecord pr = mProviderMap.get(key); if (pr == null) { return null; } @@ -4639,17 +4666,20 @@ public final class ActivityThread { } private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider, - ContentProvider localProvider,IActivityManager.ContentProviderHolder holder) { - String names[] = PATTERN_SEMICOLON.split(holder.info.authority); - ProviderClientRecord pcr = new ProviderClientRecord(names, provider, - localProvider, holder); - for (int i = 0; i < names.length; i++) { - ProviderClientRecord existing = mProviderMap.get(names[i]); + ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) { + final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority); + final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid); + + final ProviderClientRecord pcr = new ProviderClientRecord( + auths, provider, localProvider, holder); + for (String auth : auths) { + final ProviderKey key = new ProviderKey(auth, userId); + final ProviderClientRecord existing = mProviderMap.get(key); if (existing != null) { Slog.w(TAG, "Content provider " + pcr.mHolder.info.name - + " already published as " + names[i]); + + " already published as " + auth); } else { - mProviderMap.put(names[i], pcr); + mProviderMap.put(key, pcr); } } return pcr; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 56b745f..a6ec9b6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -17,6 +17,7 @@ package android.app; import com.android.internal.policy.PolicyManager; +import com.android.internal.util.Preconditions; import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; @@ -35,6 +36,7 @@ import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -183,6 +185,7 @@ class ContextImpl extends Context { private Display mDisplay; // may be null if default display private Context mReceiverRestrictedContext = null; private boolean mRestricted; + private UserHandle mUser; private final Object mSync = new Object(); @@ -1676,7 +1679,13 @@ class ContextImpl extends Context { @Override public Context createPackageContext(String packageName, int flags) - throws PackageManager.NameNotFoundException { + throws NameNotFoundException { + return createPackageContextAsUser(packageName, flags, Process.myUserHandle()); + } + + @Override + public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) + throws NameNotFoundException { if (packageName.equals("system") || packageName.equals("android")) { final ContextImpl context = new ContextImpl(mMainThread.getSystemContext()); context.mBasePackageName = mBasePackageName; @@ -1688,7 +1697,7 @@ class ContextImpl extends Context { if (pi != null) { ContextImpl c = new ContextImpl(); c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; - c.init(pi, null, mMainThread, mResources, mBasePackageName); + c.init(pi, null, mMainThread, mResources, mBasePackageName, user); if (c.mResources != null) { return c; } @@ -1769,8 +1778,8 @@ class ContextImpl extends Context { } static ContextImpl createSystemContext(ActivityThread mainThread) { - ContextImpl context = new ContextImpl(); - context.init(Resources.getSystem(), mainThread); + final ContextImpl context = new ContextImpl(); + context.init(Resources.getSystem(), mainThread, Process.myUserHandle()); return context; } @@ -1790,18 +1799,17 @@ class ContextImpl extends Context { mResources = context.mResources; mMainThread = context.mMainThread; mContentResolver = context.mContentResolver; + mUser = context.mUser; mDisplay = context.mDisplay; mOuterContext = this; } - final void init(LoadedApk packageInfo, - IBinder activityToken, ActivityThread mainThread) { - init(packageInfo, activityToken, mainThread, null, null); + final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) { + init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle()); } - final void init(LoadedApk packageInfo, - IBinder activityToken, ActivityThread mainThread, - Resources container, String basePackageName) { + final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread, + Resources container, String basePackageName, UserHandle user) { mPackageInfo = packageInfo; mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName; mResources = mPackageInfo.getResources(mainThread); @@ -1818,16 +1826,18 @@ class ContextImpl extends Context { null, container.getCompatibilityInfo()); } mMainThread = mainThread; - mContentResolver = new ApplicationContentResolver(this, mainThread); mActivityToken = activityToken; + mContentResolver = new ApplicationContentResolver(this, mainThread, user); + mUser = user; } - final void init(Resources resources, ActivityThread mainThread) { + final void init(Resources resources, ActivityThread mainThread, UserHandle user) { mPackageInfo = null; mBasePackageName = null; mResources = resources; mMainThread = mainThread; - mContentResolver = new ApplicationContentResolver(this, mainThread); + mContentResolver = new ApplicationContentResolver(this, mainThread, user); + mUser = user; } final void scheduleFinalCleanup(String who, String what) { @@ -1912,19 +1922,24 @@ class ContextImpl extends Context { // ---------------------------------------------------------------------- private static final class ApplicationContentResolver extends ContentResolver { - public ApplicationContentResolver(Context context, ActivityThread mainThread) { + private final ActivityThread mMainThread; + private final UserHandle mUser; + + public ApplicationContentResolver( + Context context, ActivityThread mainThread, UserHandle user) { super(context); - mMainThread = mainThread; + mMainThread = Preconditions.checkNotNull(mainThread); + mUser = Preconditions.checkNotNull(user); } @Override - protected IContentProvider acquireProvider(Context context, String name) { - return mMainThread.acquireProvider(context, name, true); + protected IContentProvider acquireProvider(Context context, String auth) { + return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true); } @Override - protected IContentProvider acquireExistingProvider(Context context, String name) { - return mMainThread.acquireExistingProvider(context, name, true); + protected IContentProvider acquireExistingProvider(Context context, String auth) { + return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true); } @Override @@ -1933,8 +1948,8 @@ class ContextImpl extends Context { } @Override - protected IContentProvider acquireUnstableProvider(Context c, String name) { - return mMainThread.acquireProvider(c, name, false); + protected IContentProvider acquireUnstableProvider(Context c, String auth) { + return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false); } @Override @@ -1946,7 +1961,5 @@ class ContextImpl extends Context { public void unstableProviderDied(IContentProvider icp) { mMainThread.handleUnstableProviderDied(icp.asBinder(), true); } - - private final ActivityThread mMainThread; } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index ed17d0e..2b2679e 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -117,8 +117,8 @@ public interface IActivityManager extends IInterface { public void reportThumbnail(IBinder token, Bitmap thumbnail, CharSequence description) throws RemoteException; public ContentProviderHolder getContentProvider(IApplicationThread caller, - String name, boolean stable) throws RemoteException; - public ContentProviderHolder getContentProviderExternal(String name, IBinder token) + String name, int userId, boolean stable) throws RemoteException; + public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token) throws RemoteException; public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException; public void removeContentProviderExternal(String name, IBinder token) throws RemoteException; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 17c2c6b..182ebef 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -29,6 +29,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.os.UserHandle; import android.text.TextUtils; import android.util.IntProperty; import android.util.Log; @@ -893,6 +894,19 @@ public class Notification implements Parcelable return sb.toString(); } + /** {@hide} */ + public void setUser(UserHandle user) { + if (tickerView != null) { + tickerView.setUser(user); + } + if (contentView != null) { + contentView.setUser(user); + } + if (bigContentView != null) { + bigContentView.setUser(user); + } + } + /** * Builder class for {@link Notification} objects. * diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 8fb6948..9d57467 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -265,6 +265,8 @@ public final class PendingIntent implements Parcelable { /** * @hide + * Note that UserHandle.CURRENT will be interpreted at the time the + * activity is started, not when the pending intent is created. */ public static PendingIntent getActivityAsUser(Context context, int requestCode, Intent intent, int flags, Bundle options, UserHandle user) { @@ -417,7 +419,11 @@ public final class PendingIntent implements Parcelable { new UserHandle(UserHandle.myUserId())); } - /** @hide */ + /** + * @hide + * Note that UserHandle.CURRENT will be interpreted at the time the + * broadcast is sent, not when the pending intent is created. + */ public static PendingIntent getBroadcastAsUser(Context context, int requestCode, Intent intent, int flags, UserHandle userHandle) { String packageName = context.getPackageName(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 161670f..9162d29 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -63,18 +63,34 @@ public abstract class Context { */ public static final int MODE_PRIVATE = 0x0000; /** + * @deprecated Creating world-readable files is very dangerous, and likely + * to cause security holes in applications. It is strongly discouraged; + * instead, applications should use more formal mechanism for interactions + * such as {@link ContentProvider}, {@link BroadcastReceiver}, and + * {@link android.app.Service}. There are no guarantees that this + * access mode will remain on a file, such as when it goes through a + * backup and restore. * File creation mode: allow all other applications to have read access * to the created file. * @see #MODE_PRIVATE * @see #MODE_WORLD_WRITEABLE */ + @Deprecated public static final int MODE_WORLD_READABLE = 0x0001; /** + * @deprecated Creating world-writable files is very dangerous, and likely + * to cause security holes in applications. It is strongly discouraged; + * instead, applications should use more formal mechanism for interactions + * such as {@link ContentProvider}, {@link BroadcastReceiver}, and + * {@link android.app.Service}. There are no guarantees that this + * access mode will remain on a file, such as when it goes through a + * backup and restore. * File creation mode: allow all other applications to have write access * to the created file. * @see #MODE_PRIVATE * @see #MODE_WORLD_READABLE */ + @Deprecated public static final int MODE_WORLD_WRITEABLE = 0x0002; /** * File creation mode: for use with {@link #openFileOutput}, if the file @@ -645,8 +661,12 @@ public abstract class Context { * are some important differences: * * <ul> - * <li>The platform does not monitor the space available in external storage, - * and thus will not automatically delete these files. Note that you should + * <li>The platform does not always monitor the space available in external + * storage, and thus may not automatically delete these files. Currently + * the only time files here will be deleted by the platform is when running + * on {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} or later and + * {@link android.os.Environment#isExternalStorageEmulated() + * Environment.isExternalStorageEmulated()} returns true. Note that you should * be managing the maximum space you will use for these anyway, just like * with {@link #getCacheDir()}. * <li>External files are not always available: they will disappear if the @@ -2574,6 +2594,17 @@ public abstract class Context { int flags) throws PackageManager.NameNotFoundException; /** + * Similar to {@link #createPackageContext(String, int)}, but with a + * different {@link UserHandle}. For example, {@link #getContentResolver()} + * will open any {@link Uri} as the given user. + * + * @hide + */ + public abstract Context createPackageContextAsUser( + String packageName, int flags, UserHandle user) + throws PackageManager.NameNotFoundException; + + /** * Return a new Context object for the current Context but whose resources * are adjusted to match the given Configuration. Each call to this method * returns a new instance of a Context object; Context objects are not diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 6101f4e..d824f1e 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -586,6 +586,13 @@ public class ContextWrapper extends Context { return mBase.createPackageContext(packageName, flags); } + /** @hide */ + @Override + public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) + throws PackageManager.NameNotFoundException { + return mBase.createPackageContextAsUser(packageName, flags, user); + } + @Override public Context createConfigurationContext(Configuration overrideConfiguration) { return mBase.createConfigurationContext(overrideConfiguration); diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 6b5e6e2..4257e0e 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -16,10 +16,6 @@ package android.content; -import com.android.internal.R; -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; - import android.accounts.Account; import android.accounts.AccountAndUser; import android.accounts.AccountManager; @@ -27,7 +23,6 @@ import android.accounts.AccountManagerService; import android.accounts.OnAccountsUpdateListener; import android.app.ActivityManager; import android.app.AlarmManager; -import android.app.AppGlobals; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -62,6 +57,11 @@ import android.util.EventLog; import android.util.Log; import android.util.Pair; +import com.android.internal.R; +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; +import com.google.android.collect.Sets; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -75,6 +75,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.concurrent.CountDownLatch; /** @@ -151,7 +152,7 @@ public class SyncManager implements OnAccountsUpdateListener { private AlarmManager mAlarmService = null; private SyncStorageEngine mSyncStorageEngine; - public SyncQueue mSyncQueue; + final public SyncQueue mSyncQueue; protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList(); @@ -328,7 +329,21 @@ public class SyncManager implements OnAccountsUpdateListener { private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - onUserRemoved(intent); + String action = intent.getAction(); + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (Intent.ACTION_USER_REMOVED.equals(action)) { + Log.i(TAG, "User removed - cleanup: u" + userId); + onUserRemoved(intent); + } else if (Intent.ACTION_USER_STARTED.equals(action)) { + Log.i(TAG, "User started - check alarms: u" + userId); + sendCheckAlarmsMessage(); + } else if (Intent.ACTION_USER_STOPPED.equals(action)) { + Log.i(TAG, "User stopped - stop syncs: u" + userId); + cancelActiveSync( + null /* any account */, + userId, + null /* any authority */); + } } }; @@ -401,7 +416,9 @@ public class SyncManager implements OnAccountsUpdateListener { intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_REMOVED); - mContext.registerReceiver(mUserIntentReceiver, intentFilter); + intentFilter.addAction(Intent.ACTION_USER_STARTED); + mContext.registerReceiverAsUser( + mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); if (!factoryTest) { mNotificationMgr = (NotificationManager) @@ -897,7 +914,10 @@ public class SyncManager implements OnAccountsUpdateListener { private void onUserRemoved(Intent intent) { int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); if (userId == -1) return; + removeUser(userId); + } + private void removeUser(int userId) { // Clean up the storage engine database mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId); onAccountsUpdated(null); @@ -1267,7 +1287,8 @@ public class SyncManager implements OnAccountsUpdateListener { final String accountKey; if (authority != null) { authorityName = authority.authority; - accountKey = authority.account.name + "/" + authority.account.type; + accountKey = authority.account.name + "/" + authority.account.type + + " u" + authority.userId; } else { authorityName = "Unknown"; accountKey = "Unknown"; @@ -1394,7 +1415,8 @@ public class SyncManager implements OnAccountsUpdateListener { final String accountKey; if (authority != null) { authorityName = authority.authority; - accountKey = authority.account.name + "/" + authority.account.type; + accountKey = authority.account.name + "/" + authority.account.type + + " u" + authority.userId; } else { authorityName = "Unknown"; accountKey = "Unknown"; @@ -1924,6 +1946,10 @@ public class SyncManager implements OnAccountsUpdateListener { } Iterator<SyncOperation> operationIterator = mSyncQueue.mOperationsMap.values().iterator(); + + final ActivityManager activityManager + = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + final Set<Integer> removedUsers = Sets.newHashSet(); while (operationIterator.hasNext()) { final SyncOperation op = operationIterator.next(); @@ -1943,6 +1969,15 @@ public class SyncManager implements OnAccountsUpdateListener { continue; } + // if the user in not running, drop the request + if (!activityManager.isUserRunning(op.userId)) { + final UserInfo userInfo = mUserManager.getUserInfo(op.userId); + if (userInfo == null) { + removedUsers.add(op.userId); + } + continue; + } + // if the next run time is in the future, meaning there are no syncs ready // to run, return the time if (op.effectiveRunTime > now) { @@ -1983,6 +2018,12 @@ public class SyncManager implements OnAccountsUpdateListener { operations.add(op); } + for (Integer user : removedUsers) { + // if it's still removed + if (mUserManager.getUserInfo(user) == null) { + removeUser(user); + } + } } // find the next operation to dispatch, if one is ready @@ -2168,13 +2209,13 @@ public class SyncManager implements OnAccountsUpdateListener { new ArrayList<ActiveSyncContext>(mActiveSyncContexts); for (ActiveSyncContext activeSyncContext : activeSyncs) { if (activeSyncContext != null) { - // if an authority was specified then only cancel the sync if it matches + // if an account was specified then only cancel the sync if it matches if (account != null) { if (!account.equals(activeSyncContext.mSyncOperation.account)) { continue; } } - // if an account was specified then only cancel the sync if it matches + // if an authority was specified then only cancel the sync if it matches if (authority != null) { if (!authority.equals(activeSyncContext.mSyncOperation.authority)) { continue; diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java index 9fcc22d..6611fcd 100644 --- a/core/java/android/content/SyncOperation.java +++ b/core/java/android/content/SyncOperation.java @@ -95,13 +95,18 @@ public class SyncOperation implements Comparable { } public String dump(boolean useOneLine) { - StringBuilder sb = new StringBuilder(); - sb.append(account.name); - sb.append(" (" + account.type + ")"); - sb.append(", " + authority); - sb.append(", "); - sb.append(SyncStorageEngine.SOURCES[syncSource]); - sb.append(", earliestRunTime " + earliestRunTime); + StringBuilder sb = new StringBuilder() + .append(account.name) + .append(" u") + .append(userId).append(" (") + .append(account.type) + .append(")") + .append(", ") + .append(authority) + .append(", ") + .append(SyncStorageEngine.SOURCES[syncSource]) + .append(", earliestRunTime ") + .append(earliestRunTime); if (expedited) { sb.append(", EXPEDITED"); } diff --git a/core/java/android/content/pm/PackageCleanItem.java b/core/java/android/content/pm/PackageCleanItem.java index eea3b9c..b1896aa 100644 --- a/core/java/android/content/pm/PackageCleanItem.java +++ b/core/java/android/content/pm/PackageCleanItem.java @@ -21,10 +21,12 @@ import android.os.Parcelable; /** @hide */ public class PackageCleanItem { + public final int userId; public final String packageName; public final boolean andCode; - public PackageCleanItem(String packageName, boolean andCode) { + public PackageCleanItem(int userId, String packageName, boolean andCode) { + this.userId = userId; this.packageName = packageName; this.andCode = andCode; } @@ -37,7 +39,8 @@ public class PackageCleanItem { try { if (obj != null) { PackageCleanItem other = (PackageCleanItem)obj; - return packageName.equals(other.packageName) && andCode == other.andCode; + return userId == other.userId && packageName.equals(other.packageName) + && andCode == other.andCode; } } catch (ClassCastException e) { } @@ -47,6 +50,7 @@ public class PackageCleanItem { @Override public int hashCode() { int result = 17; + result = 31 * result + userId; result = 31 * result + packageName.hashCode(); result = 31 * result + (andCode ? 1 : 0); return result; @@ -57,6 +61,7 @@ public class PackageCleanItem { } public void writeToParcel(Parcel dest, int parcelableFlags) { + dest.writeInt(userId); dest.writeString(packageName); dest.writeInt(andCode ? 1 : 0); } @@ -73,6 +78,7 @@ public class PackageCleanItem { }; private PackageCleanItem(Parcel source) { + userId = source.readInt(); packageName = source.readString(); andCode = source.readInt() != 0; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 59b057a..291726a 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -837,7 +837,6 @@ public abstract class PackageManager { * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has at least one camera pointing in * some direction. - * @hide */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any"; diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index e3749b4..07117fe 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -230,6 +230,21 @@ public class ResolveInfo implements Parcelable { public ResolveInfo() { } + public ResolveInfo(ResolveInfo orig) { + activityInfo = orig.activityInfo; + serviceInfo = orig.serviceInfo; + filter = orig.filter; + priority = orig.priority; + preferredOrder = orig.preferredOrder; + match = orig.match; + specificIndex = orig.specificIndex; + labelRes = orig.labelRes; + nonLocalizedLabel = orig.nonLocalizedLabel; + icon = orig.icon; + resolvePackageName = orig.resolvePackageName; + system = orig.system; + } + public String toString() { ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo; return "ResolveInfo{" diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 375d788..1e8671b 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -1161,25 +1161,28 @@ public class Camera { public native final void setDisplayOrientation(int degrees); /** - * Enable or disable the default shutter sound when taking a picture. + * <p>Enable or disable the default shutter sound when taking a picture.</p> * - * By default, the camera plays the system-defined camera shutter sound when - * {@link #takePicture} is called. Using this method, the shutter sound can - * be disabled. It is strongly recommended that an alternative shutter sound - * is played in the {@link ShutterCallback} when the system shutter sound is - * disabled. + * <p>By default, the camera plays the system-defined camera shutter sound + * when {@link #takePicture} is called. Using this method, the shutter sound + * can be disabled. It is strongly recommended that an alternative shutter + * sound is played in the {@link ShutterCallback} when the system shutter + * sound is disabled.</p> * - * Note that devices may not always allow control of the camera shutter - * sound. If the shutter sound cannot be controlled, this method will return - * false. + * <p>Note that devices may not always allow disabling the camera shutter + * sound. If the shutter sound state cannot be set to the desired value, + * this method will return false. {@link CameraInfo#canDisableShutterSound} + * can be used to determine whether the device will allow the shutter sound + * to be disabled.</p> * * @param enabled whether the camera should play the system shutter sound * when {@link #takePicture takePicture} is called. - * @return true if the shutter sound state was successfully changed. False - * if the shutter sound cannot be controlled; in this case, the - * application should not play its own shutter sound since the - * system shutter sound will play when a picture is taken. + * @return {@code true} if the shutter sound state was successfully + * changed. {@code false} if the shutter sound state could not be + * changed. {@code true} is also returned if shutter sound playback + * is already set to the requested state. * @see #takePicture + * @see CameraInfo#canDisableShutterSound * @see ShutterCallback */ public native final boolean enableShutterSound(boolean enabled); diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 27cabef..846443d 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -21,6 +21,7 @@ import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; +import java.net.SocketException; import java.security.KeyManagementException; import java.security.cert.X509Certificate; import javax.net.SocketFactory; @@ -341,6 +342,22 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { castToOpenSSLSocket(socket).setHostname(hostName); } + /** + * Sets this socket's SO_SNDTIMEO write timeout in milliseconds. + * Use 0 for no timeout. + * To take effect, this option must be set before the blocking method was called. + * + * @param socket a socket created by this factory. + * @param timeout the desired write timeout in milliseconds. + * @throws IllegalArgumentException if the socket was not created by this factory. + * + * @hide + */ + public void setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds) + throws SocketException { + castToOpenSSLSocket(socket).setSoWriteTimeout(writeTimeoutMilliseconds); + } + private static OpenSSLSocketImpl castToOpenSSLSocket(Socket socket) { if (!(socket instanceof OpenSSLSocketImpl)) { throw new IllegalArgumentException("Socket not created by this factory: " diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java index a31cb9c..64aa299 100644 --- a/core/java/android/nfc/tech/Ndef.java +++ b/core/java/android/nfc/tech/Ndef.java @@ -140,8 +140,8 @@ public final class Ndef extends BasicTagTechnology { * * <p>Does not cause any RF activity and does not block. * - * @param tag an MIFARE Classic compatible tag - * @return MIFARE Classic object + * @param tag an NDEF compatible tag + * @return Ndef object */ public static Ndef get(Tag tag) { if (!tag.hasTech(TagTechnology.NDEF)) return null; diff --git a/core/java/android/nfc/tech/NfcBarcode.java b/core/java/android/nfc/tech/NfcBarcode.java new file mode 100644 index 0000000..099f07e --- /dev/null +++ b/core/java/android/nfc/tech/NfcBarcode.java @@ -0,0 +1,102 @@ +/* + * 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.nfc.tech; + +import android.nfc.Tag; +import android.os.Bundle; +import android.os.RemoteException; + +/** + * Provides access to tags containing just a barcode. + * + * <p>Acquire an {@link NfcBarcode} object using {@link #get}. + * + */ +public final class NfcBarcode extends BasicTagTechnology { + + /** Kovio Tags */ + public static final int TYPE_KOVIO = 1; + public static final int TYPE_UNKNOWN = -1; + + /** @hide */ + public static final String EXTRA_BARCODE_TYPE = "barcodetype"; + + private int mType; + + /** + * Get an instance of {@link NfcBarcode} for the given tag. + * + * <p>Returns null if {@link NfcBarcode} was not enumerated in {@link Tag#getTechList}. + * + * <p>Does not cause any RF activity and does not block. + * + * @param tag an NfcBarcode compatible tag + * @return NfcBarcode object + */ + public static NfcBarcode get(Tag tag) { + if (!tag.hasTech(TagTechnology.NFC_BARCODE)) return null; + try { + return new NfcBarcode(tag); + } catch (RemoteException e) { + return null; + } + } + + /** + * Internal constructor, to be used by NfcAdapter + * @hide + */ + public NfcBarcode(Tag tag) throws RemoteException { + super(tag, TagTechnology.NFC_BARCODE); + Bundle extras = tag.getTechExtras(TagTechnology.NFC_BARCODE); + if (extras != null) { + mType = extras.getInt(EXTRA_BARCODE_TYPE); + } else { + throw new NullPointerException("NfcBarcode tech extras are null."); + } + } + + /** + * Returns the NFC Barcode tag type. + * + * <p>Currently only one of {@link #TYPE_KOVIO} or {@link TYPE_UNKNOWN}. + * + * <p>Does not cause any RF activity and does not block. + * + * @return the NFC Barcode tag type + */ + public int getType() { + return mType; + } + + /** + * Returns the barcode of an NfcBarcode tag. + * + * <p>Does not cause any RF activity and does not block. + * + * @return a byte array containing the barcode + */ + public byte[] getBarcode() { + switch (mType) { + case TYPE_KOVIO: + // For Kovio tags the barcode matches the ID + return mTag.getId(); + default: + return null; + } + } +} diff --git a/core/java/android/nfc/tech/TagTechnology.java b/core/java/android/nfc/tech/TagTechnology.java index be5cbd2..3493ea7 100644 --- a/core/java/android/nfc/tech/TagTechnology.java +++ b/core/java/android/nfc/tech/TagTechnology.java @@ -148,6 +148,15 @@ public interface TagTechnology extends Closeable { public static final int MIFARE_ULTRALIGHT = 9; /** + * This technology is an instance of {@link NfcBarcode}. + * <p>Support for this technology type is optional. If a stack doesn't support this technology + * type tags using it must still be discovered and present the lower level radio interface + * technologies in use. + * @hide + */ + public static final int NFC_BARCODE = 10; + + /** * Get the {@link Tag} object backing this {@link TagTechnology} object. * @return the {@link Tag} backing this {@link TagTechnology} object. */ diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index a28585c..fd0324b 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -467,6 +467,13 @@ public final class CalendarContract { * */ public static final String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes"; + + /** + * Is this the primary calendar for this account. If this column is not explicitly set, the + * provider will return 1 if {@link Calendars#ACCOUNT_NAME} is equal to + * {@link Calendars#OWNER_ACCOUNT}. + */ + public static final String IS_PRIMARY = "isPrimary"; } /** @@ -1206,6 +1213,14 @@ public final class CalendarContract { public static final String ORGANIZER = "organizer"; /** + * Are we the organizer of this event. If this column is not explicitly set, the provider + * will return 1 if {@link #ORGANIZER} is equal to {@link Calendars#OWNER_ACCOUNT}. + * Column name. + * <P>Type: STRING</P> + */ + public static final String IS_ORGANIZER = "isOrganizer"; + + /** * Whether the user can invite others to the event. The * GUESTS_CAN_INVITE_OTHERS is a setting that applies to an arbitrary * guest, while CAN_INVITE_OTHERS indicates if the user can invite @@ -1368,6 +1383,7 @@ public final class CalendarContract { DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CUSTOM_APP_PACKAGE); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CUSTOM_APP_URI); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ORGANIZER); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, IS_ORGANIZER); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_ID); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY); DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, LAST_SYNCED); diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 3c90f1c..0e7ab52 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -255,7 +255,6 @@ public final class MediaStore { * * @see #ACTION_IMAGE_CAPTURE * @see #EXTRA_OUTPUT - * @hide */ public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7864302..9aae1ec 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -764,10 +764,6 @@ public final class Settings { return true; } - public boolean putString(ContentResolver cr, String name, String value) { - return putStringForUser(cr, name, value, UserHandle.myUserId()); - } - public String getStringForUser(ContentResolver cr, String name, final int userHandle) { final boolean isSelf = (userHandle == UserHandle.myUserId()); if (isSelf) { @@ -855,10 +851,6 @@ public final class Settings { if (c != null) c.close(); } } - - public String getString(ContentResolver cr, String name) { - return getStringForUser(cr, name, UserHandle.myUserId()); - } } /** @@ -869,8 +861,17 @@ public final class Settings { public static final class System extends NameValueTable { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version"; - // Populated lazily, guarded by class object: - private static NameValueCache sNameValueCache = null; + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/system"); + + private static final NameValueCache sNameValueCache = new NameValueCache( + SYS_PROP_SETTING_VERSION, + CONTENT_URI, + CALL_METHOD_GET_SYSTEM, + CALL_METHOD_PUT_SYSTEM); private static final HashSet<String> MOVED_TO_SECURE; static { @@ -937,28 +938,18 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.MODE_RINGER); } - private static void lazyInitCache() { - if (sNameValueCache == null) { - sNameValueCache = new NameValueCache( - SYS_PROP_SETTING_VERSION + '_' + UserHandle.myUserId(), - CONTENT_URI, - CALL_METHOD_GET_SYSTEM, - CALL_METHOD_PUT_SYSTEM); - } - } - /** * Look up a name in the database. * @param resolver to access the database with * @param name to look up in the table * @return the corresponding value, or null if not present */ - public synchronized static String getString(ContentResolver resolver, String name) { + public static String getString(ContentResolver resolver, String name) { return getStringForUser(resolver, name, UserHandle.myUserId()); } /** @hide */ - public synchronized static String getStringForUser(ContentResolver resolver, String name, + public static String getStringForUser(ContentResolver resolver, String name, int userHandle) { if (MOVED_TO_SECURE.contains(name)) { Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" @@ -970,7 +961,6 @@ public final class Settings { + " to android.provider.Settings.Global, returning read-only value."); return Global.getStringForUser(resolver, name, userHandle); } - lazyInitCache(); return sNameValueCache.getStringForUser(resolver, name, userHandle); } @@ -998,7 +988,6 @@ public final class Settings { + " to android.provider.Settings.Global, value is unchanged."); return false; } - lazyInitCache(); return sNameValueCache.putStringForUser(resolver, name, value, userHandle); } @@ -1368,12 +1357,6 @@ public final class Settings { } /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://" + AUTHORITY + "/system"); - - /** * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead */ @Deprecated @@ -2549,8 +2532,18 @@ public final class Settings { public static final class Secure extends NameValueTable { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version"; + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/secure"); + // Populated lazily, guarded by class object: - private static NameValueCache sNameValueCache = null; + private static final NameValueCache sNameValueCache = new NameValueCache( + SYS_PROP_SETTING_VERSION, + CONTENT_URI, + CALL_METHOD_GET_SECURE, + CALL_METHOD_PUT_SECURE); private static ILockSettings sLockSettings = null; @@ -2654,28 +2647,18 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.WTF_IS_FATAL); } - private static void lazyInitCache() { - if (sNameValueCache == null) { - sNameValueCache = new NameValueCache( - SYS_PROP_SETTING_VERSION + '_' + UserHandle.myUserId(), - CONTENT_URI, - CALL_METHOD_GET_SECURE, - CALL_METHOD_PUT_SECURE); - } - } - /** * Look up a name in the database. * @param resolver to access the database with * @param name to look up in the table * @return the corresponding value, or null if not present */ - public synchronized static String getString(ContentResolver resolver, String name) { + public static String getString(ContentResolver resolver, String name) { return getStringForUser(resolver, name, UserHandle.myUserId()); } /** @hide */ - public synchronized static String getStringForUser(ContentResolver resolver, String name, + public static String getStringForUser(ContentResolver resolver, String name, int userHandle) { if (MOVED_TO_GLOBAL.contains(name)) { Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" @@ -2683,21 +2666,23 @@ public final class Settings { return Global.getStringForUser(resolver, name, userHandle); } - if (sLockSettings == null) { - sLockSettings = ILockSettings.Stub.asInterface( - (IBinder) ServiceManager.getService("lock_settings")); - sIsSystemProcess = Process.myUid() == Process.SYSTEM_UID; - } - if (sLockSettings != null && !sIsSystemProcess - && MOVED_TO_LOCK_SETTINGS.contains(name)) { - try { - return sLockSettings.getString(name, "0", userHandle); - } catch (RemoteException re) { - // Fall through + if (MOVED_TO_LOCK_SETTINGS.contains(name)) { + synchronized (Secure.class) { + if (sLockSettings == null) { + sLockSettings = ILockSettings.Stub.asInterface( + (IBinder) ServiceManager.getService("lock_settings")); + sIsSystemProcess = Process.myUid() == Process.SYSTEM_UID; + } + } + if (sLockSettings != null && !sIsSystemProcess) { + try { + return sLockSettings.getString(name, "0", userHandle); + } catch (RemoteException re) { + // Fall through + } } } - lazyInitCache(); return sNameValueCache.getStringForUser(resolver, name, userHandle); } @@ -2720,7 +2705,6 @@ public final class Settings { + " to android.provider.Settings.Global"); return Global.putStringForUser(resolver, name, value, userHandle); } - lazyInitCache(); return sNameValueCache.putStringForUser(resolver, name, value, userHandle); } @@ -3001,12 +2985,6 @@ public final class Settings { } /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://" + AUTHORITY + "/secure"); - - /** * @deprecated Use {@link android.provider.Settings.Global#DEVELOPMENT_SETTINGS_ENABLED} * instead */ @@ -5467,11 +5445,21 @@ public final class Settings { /** * Used to disable SMS short code confirmation - defaults to true. + * True indcates we will do the check, etc. Set to false to disable. * @see com.android.internal.telephony.SmsUsageMonitor * @hide */ public static final String SMS_SHORT_CODE_CONFIRMATION = "sms_short_code_confirmation"; + /** + * Used to select which country we use to determine premium sms codes. + * One of com.android.internal.telephony.SMSDispatcher.PREMIUM_RULE_USE_SIM, + * com.android.internal.telephony.SMSDispatcher.PREMIUM_RULE_USE_NETWORK, + * or com.android.internal.telephony.SMSDispatcher.PREMIUM_RULE_USE_BOTH. + * @hide + */ + public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule"; + /** * Prefix for SMS short code regex patterns (country code is appended). * @see com.android.internal.telephony.SmsUsageMonitor @@ -5755,17 +5743,11 @@ public final class Settings { // Populated lazily, guarded by class object: - private static NameValueCache sNameValueCache = null; - - private static void lazyInitCache() { - if (sNameValueCache == null) { - sNameValueCache = new NameValueCache( - SYS_PROP_SETTING_VERSION, - CONTENT_URI, - CALL_METHOD_GET_GLOBAL, - CALL_METHOD_PUT_GLOBAL); - } - } + private static NameValueCache sNameValueCache = new NameValueCache( + SYS_PROP_SETTING_VERSION, + CONTENT_URI, + CALL_METHOD_GET_GLOBAL, + CALL_METHOD_PUT_GLOBAL); /** * Look up a name in the database. @@ -5773,14 +5755,13 @@ public final class Settings { * @param name to look up in the table * @return the corresponding value, or null if not present */ - public synchronized static String getString(ContentResolver resolver, String name) { + public static String getString(ContentResolver resolver, String name) { return getStringForUser(resolver, name, UserHandle.myUserId()); } /** @hide */ - public synchronized static String getStringForUser(ContentResolver resolver, String name, + public static String getStringForUser(ContentResolver resolver, String name, int userHandle) { - lazyInitCache(); return sNameValueCache.getStringForUser(resolver, name, userHandle); } @@ -5799,7 +5780,6 @@ public final class Settings { /** @hide */ public static boolean putStringForUser(ContentResolver resolver, String name, String value, int userHandle) { - lazyInitCache(); if (LOCAL_LOGV) { Log.v(TAG, "Global.putString(name=" + name + ", value=" + value + " for " + userHandle); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 31bbc6a..30b8b85 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3927,7 +3927,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } // Apply layout direction to the new Drawables if needed - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); if (track != null) { track.setLayoutDirection(layoutDirection); } @@ -5779,7 +5779,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") }) - public int getLayoutDirection() { + private int getRawLayoutDirection() { return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; } @@ -5796,16 +5796,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @RemotableViewMethod public void setLayoutDirection(int layoutDirection) { - if (getLayoutDirection() != layoutDirection) { + if (getRawLayoutDirection() != layoutDirection) { // Reset the current layout direction and the resolved one mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; - resetResolvedLayoutDirection(); - // Reset padding resolution - mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; + resetRtlProperties(); // Set the new layout direction (filtered) mPrivateFlags2 |= ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); resolveRtlProperties(); + // Notify changes + onRtlPropertiesChanged(); // ... and ask for a layout pass requestLayout(); } @@ -5821,7 +5821,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") }) - public int getResolvedLayoutDirection() { + public int getLayoutDirection() { final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; if (targetSdkVersion < JELLY_BEAN_MR1) { mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; @@ -5843,7 +5843,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @ViewDebug.ExportedProperty(category = "layout") public boolean isLayoutRtl() { - return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL); + return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); } /** @@ -9936,7 +9936,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private void resolveLayoutParams() { if (mLayoutParams != null) { - mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection()); + mLayoutParams.onResolveLayoutDirection(getLayoutDirection()); } } @@ -11475,6 +11475,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, jumpDrawablesToCurrentState(); resolveRtlProperties(); + // Notify changes + onRtlPropertiesChanged(); clearAccessibilityFocus(); if (isFocused()) { @@ -11487,17 +11489,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + /** + * Resolve all RTL related properties + */ void resolveRtlProperties() { // Order is important here: LayoutDirection MUST be resolved first... resolveLayoutDirection(); // ... then we can resolve the others properties depending on the resolved LayoutDirection. - resolvePadding(); - resolveLayoutParams(); resolveTextDirection(); resolveTextAlignment(); + resolvePadding(); + resolveLayoutParams(); resolveDrawables(); } + // Reset resolution of all RTL related properties + void resetRtlProperties() { + resetResolvedLayoutDirection(); + resetResolvedTextDirection(); + resetResolvedTextAlignment(); + resetResolvedPadding(); + } + /** * @see #onScreenStateChanged(int) */ @@ -11525,9 +11538,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Called when any RTL property (layout direction or text direction or text alignment) has + * been changed. + * + * Subclasses need to override this method to take care of cached information that depends on the + * resolved layout direction, or to inform child views that inherit their layout direction. + * + * The default implementation does nothing. + */ + public void onRtlPropertiesChanged() { + } + + /** * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing * that the parent directionality can and will be resolved before its children. - * Will call {@link View#onResolvedLayoutDirectionChanged} when resolution is done. + * + * @hide */ public void resolveLayoutDirection() { // Clear any previous layout direction resolution @@ -11535,7 +11561,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (hasRtlSupport()) { // Set resolved depending on layout direction - switch (getLayoutDirection()) { + switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> + PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { case LAYOUT_DIRECTION_INHERIT: // We cannot resolve yet. LTR is by default and let the resolution happen again // later to get the correct resolved value @@ -11547,7 +11574,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // resolution happen again later if (!viewGroup.canResolveLayoutDirection()) return; - if (viewGroup.getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) { + if (viewGroup.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; } break; @@ -11555,7 +11582,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; break; case LAYOUT_DIRECTION_LOCALE: - if(isLayoutDirectionRtl(Locale.getDefault())) { + if((LAYOUT_DIRECTION_RTL == + TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; } break; @@ -11566,19 +11594,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Set to resolved mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; - onResolvedLayoutDirectionChanged(); } /** - * Called when layout direction has been resolved. + * Check if layout direction resolution can be done. * - * The default implementation does nothing. + * @return true if layout direction resolution can be done otherwise return false. + * + * @hide + */ + public boolean canResolveLayoutDirection() { + switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> + PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { + case LAYOUT_DIRECTION_INHERIT: + return (mParent != null) && (mParent instanceof ViewGroup); + default: + return true; + } + } + + /** + * Reset the resolved layout direction. + * + * @hide */ - public void onResolvedLayoutDirectionChanged() { + public void resetResolvedLayoutDirection() { + // Reset the current resolved bits + mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; + } + + /** + * @hide + */ + public boolean isLayoutDirectionInherited() { + return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); } /** * Return if padding has been resolved + * + * @hide */ boolean isPaddingResolved() { return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) != 0; @@ -11586,6 +11641,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Resolve padding depending on layout direction. + * + * @hide */ public void resolvePadding() { final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; @@ -11612,7 +11669,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // If start / end padding are defined, they will be resolved (hence overriding) to // left / right or right / left depending on the resolved layout direction. // If start / end padding are not defined, use the left / right ones. - int resolvedLayoutDirection = getResolvedLayoutDirection(); + int resolvedLayoutDirection = getLayoutDirection(); // Set user padding to initial values ... mUserPaddingLeft = (mUserPaddingLeftInitial == UNDEFINED_PADDING) ? 0 : mUserPaddingLeftInitial; @@ -11649,6 +11706,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Reset the resolved layout direction. + * + * @hide + */ + public void resetResolvedPadding() { + mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; + } + + /** * Resolve padding depending on the layout direction. Subclasses that care about * padding resolution should override this method. The default implementation does * nothing. @@ -11662,53 +11728,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Check if layout direction resolution can be done. - * - * @return true if layout direction resolution can be done otherwise return false. - */ - public boolean canResolveLayoutDirection() { - switch (getLayoutDirection()) { - case LAYOUT_DIRECTION_INHERIT: - return (mParent != null) && (mParent instanceof ViewGroup); - default: - return true; - } - } - - /** - * Reset the resolved layout direction. Will call {@link View#onResolvedLayoutDirectionReset} - * when reset is done. - */ - public void resetResolvedLayoutDirection() { - // Reset the current resolved bits - mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; - onResolvedLayoutDirectionReset(); - // Reset also the text direction - resetResolvedTextDirection(); - } - - /** - * Called during reset of resolved layout direction. - * - * Subclasses need to override this method to clear cached information that depends on the - * resolved layout direction, or to inform child views that inherit their layout direction. - * - * The default implementation does nothing. - */ - public void onResolvedLayoutDirectionReset() { - } - - /** - * Check if a Locale uses an RTL script. - * - * @param locale Locale to check - * @return true if the Locale uses an RTL script. - */ - protected static boolean isLayoutDirectionRtl(Locale locale) { - return (LAYOUT_DIRECTION_RTL == TextUtils.getLayoutDirectionFromLocale(locale)); - } - - /** * This is called when the view is detached from a window. At this point it * no longer has a surface for drawing. * @@ -11738,10 +11757,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mCurrentAnimation = null; - resetResolvedLayoutDirection(); - resetResolvedTextAlignment(); + resetRtlProperties(); + onRtlPropertiesChanged(); resetAccessibilityStateChanged(); - mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; } /** @@ -14091,12 +14109,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * that the View directionality can and will be resolved before its Drawables. * * Will call {@link View#onResolveDrawables} when resolution is done. + * + * @hide */ public void resolveDrawables() { if (mBackground != null) { - mBackground.setLayoutDirection(getResolvedLayoutDirection()); + mBackground.setLayoutDirection(getLayoutDirection()); } - onResolveDrawables(getResolvedLayoutDirection()); + onResolveDrawables(getLayoutDirection()); } /** @@ -14108,6 +14128,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @see #LAYOUT_DIRECTION_LTR * @see #LAYOUT_DIRECTION_RTL + * + * @hide */ public void onResolveDrawables(int layoutDirection) { } @@ -14381,10 +14403,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, padding = new Rect(); sThreadLocal.set(padding); } - background.setLayoutDirection(getResolvedLayoutDirection()); + background.setLayoutDirection(getLayoutDirection()); if (background.getPadding(padding)) { - // Reset padding resolution - mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; + resetResolvedPadding(); switch (background.getLayoutDirection()) { case LAYOUT_DIRECTION_RTL: mUserPaddingLeftInitial = padding.right; @@ -14485,8 +14506,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param bottom the bottom padding in pixels */ public void setPadding(int left, int top, int right, int bottom) { - // Reset padding resolution - mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; + resetResolvedPadding(); mUserPaddingStart = UNDEFINED_PADDING; mUserPaddingEnd = UNDEFINED_PADDING; @@ -14575,13 +14595,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param bottom the bottom padding in pixels */ public void setPaddingRelative(int start, int top, int end, int bottom) { - // Reset padding resolution - mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; + resetResolvedPadding(); mUserPaddingStart = start; mUserPaddingEnd = end; - switch(getResolvedLayoutDirection()) { + switch(getLayoutDirection()) { case LAYOUT_DIRECTION_RTL: mUserPaddingLeftInitial = end; mUserPaddingRightInitial = start; @@ -14640,7 +14659,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!isPaddingResolved()) { resolvePadding(); } - return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ? + return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? mPaddingRight : mPaddingLeft; } @@ -14669,7 +14688,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!isPaddingResolved()) { resolvePadding(); } - return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ? + return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? mPaddingLeft : mPaddingRight; } @@ -16481,6 +16500,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE} + * + * @hide */ @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), @@ -16490,7 +16511,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE") }) - public int getTextDirection() { + public int getRawTextDirection() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; } @@ -16507,12 +16528,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_DIRECTION_LOCALE} */ public void setTextDirection(int textDirection) { - if (getTextDirection() != textDirection) { + if (getRawTextDirection() != textDirection) { // Reset the current text direction and the resolved one mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; resetResolvedTextDirection(); // Set the new text direction mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); + // Notify change + onRtlPropertiesChanged(); // Refresh requestLayout(); invalidate(true); @@ -16522,10 +16545,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Return the resolved text direction. * - * This needs resolution if the value is TEXT_DIRECTION_INHERIT. The resolution matches - * {@link #getTextDirection()}if it is not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds - * up the parent chain of the view. if there is no parent, then it will return the default - * {@link #TEXT_DIRECTION_FIRST_STRONG}. + * This needs resolution if the value is TEXT_DIRECTION_INHERIT. The resolution matches what has + * been set by {@link #setTextDirection(int)} if it is not TEXT_DIRECTION_INHERIT, otherwise the + * resolution proceeds up the parent chain of the view. If there is no parent, then it will + * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. * * @return the resolved text direction. Returns one of: * @@ -16535,7 +16558,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE} */ - public int getResolvedTextDirection() { + public int getTextDirection() { // The text direction will be resolved only if needed if ((mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) != PFLAG2_TEXT_DIRECTION_RESOLVED) { resolveTextDirection(); @@ -16544,8 +16567,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Resolve the text direction. Will call {@link View#onResolvedTextDirectionChanged} when - * resolution is done. + * Resolve the text direction. + * + * @hide */ public void resolveTextDirection() { // Reset any previous text direction resolution @@ -16553,14 +16577,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (hasRtlSupport()) { // Set resolved text direction flag depending on text direction flag - final int textDirection = getTextDirection(); + final int textDirection = getRawTextDirection(); switch(textDirection) { case TEXT_DIRECTION_INHERIT: if (canResolveTextDirection()) { ViewGroup viewGroup = ((ViewGroup) mParent); // Set current resolved direction to the same value as the parent's one - final int parentResolvedDirection = viewGroup.getResolvedTextDirection(); + final int parentResolvedDirection = viewGroup.getTextDirection(); switch (parentResolvedDirection) { case TEXT_DIRECTION_FIRST_STRONG: case TEXT_DIRECTION_ANY_RTL: @@ -16598,16 +16622,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Set to resolved mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; - onResolvedTextDirectionChanged(); - } - - /** - * Called when text direction has been resolved. Subclasses that care about text direction - * resolution should override this method. - * - * The default implementation does nothing. - */ - public void onResolvedTextDirectionChanged() { } /** @@ -16615,8 +16629,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @return true if text direction resolution can be done otherwise return false. */ - public boolean canResolveTextDirection() { - switch (getTextDirection()) { + private boolean canResolveTextDirection() { + switch (getRawTextDirection()) { case TEXT_DIRECTION_INHERIT: return (mParent != null) && (mParent instanceof ViewGroup); default: @@ -16626,20 +16640,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Reset resolved text direction. Text direction can be resolved with a call to - * getResolvedTextDirection(). Will call {@link View#onResolvedTextDirectionReset} when - * reset is done. + * getTextDirection(). + * + * @hide */ public void resetResolvedTextDirection() { mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); - onResolvedTextDirectionReset(); } /** - * Called when text direction is reset. Subclasses that care about text direction reset should - * override this method and do a reset of the text direction of their children. The default - * implementation does nothing. + * @hide */ - public void onResolvedTextDirectionReset() { + public boolean isTextDirectionInherited() { + return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); } /** @@ -16655,6 +16668,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #TEXT_ALIGNMENT_TEXT_END}, * {@link #TEXT_ALIGNMENT_VIEW_START}, * {@link #TEXT_ALIGNMENT_VIEW_END} + * + * @hide */ @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), @@ -16665,7 +16680,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") }) - public int getTextAlignment() { + public int getRawTextAlignment() { return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; } @@ -16685,12 +16700,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @attr ref android.R.styleable#View_textAlignment */ public void setTextAlignment(int textAlignment) { - if (textAlignment != getTextAlignment()) { + if (textAlignment != getRawTextAlignment()) { // Reset the current and resolved text alignment mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; resetResolvedTextAlignment(); // Set the new text alignment mPrivateFlags2 |= ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); + // Notify change + onRtlPropertiesChanged(); // Refresh requestLayout(); invalidate(true); @@ -16722,7 +16739,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") }) - public int getResolvedTextAlignment() { + public int getTextAlignment() { // If text alignment is not resolved, then resolve it if ((mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) != PFLAG2_TEXT_ALIGNMENT_RESOLVED) { resolveTextAlignment(); @@ -16731,8 +16748,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Resolve the text alignment. Will call {@link View#onResolvedTextAlignmentChanged} when - * resolution is done. + * Resolve the text alignment. + * + * @hide */ public void resolveTextAlignment() { // Reset any previous text alignment resolution @@ -16740,14 +16758,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (hasRtlSupport()) { // Set resolved text alignment flag depending on text alignment flag - final int textAlignment = getTextAlignment(); + final int textAlignment = getRawTextAlignment(); switch (textAlignment) { case TEXT_ALIGNMENT_INHERIT: // Check if we can resolve the text alignment - if (canResolveLayoutDirection() && mParent instanceof View) { + if (canResolveTextAlignment() && mParent instanceof View) { View view = (View) mParent; - final int parentResolvedTextAlignment = view.getResolvedTextAlignment(); + final int parentResolvedTextAlignment = view.getTextAlignment(); switch (parentResolvedTextAlignment) { case TEXT_ALIGNMENT_GRAVITY: case TEXT_ALIGNMENT_TEXT_START: @@ -16790,7 +16808,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Set the resolved mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; - onResolvedTextAlignmentChanged(); } /** @@ -16798,8 +16815,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @return true if text alignment resolution can be done otherwise return false. */ - public boolean canResolveTextAlignment() { - switch (getTextAlignment()) { + private boolean canResolveTextAlignment() { + switch (getRawTextAlignment()) { case TEXT_DIRECTION_INHERIT: return (mParent != null); default: @@ -16808,31 +16825,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Called when text alignment has been resolved. Subclasses that care about text alignment - * resolution should override this method. + * Reset resolved text alignment. * - * The default implementation does nothing. - */ - public void onResolvedTextAlignmentChanged() { - } - - /** - * Reset resolved text alignment. Text alignment can be resolved with a call to - * getResolvedTextAlignment(). Will call {@link View#onResolvedTextAlignmentReset} when - * reset is done. + * @hide */ public void resetResolvedTextAlignment() { // Reset any previous text alignment resolution mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); - onResolvedTextAlignmentReset(); } /** - * Called when text alignment is reset. Subclasses that care about text alignment reset should - * override this method and do a reset of the text alignment of their children. The default - * implementation does nothing. + * @hide */ - public void onResolvedTextAlignmentReset() { + public boolean isTextAlignmentInherited() { + return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index ae10fbe..34411ea 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3392,7 +3392,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager childHasTransientStateChanged(child, true); } - if (child.getLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { + if (child.isLayoutDirectionInherited()) { child.resetResolvedLayoutDirection(); child.resolveRtlProperties(); } @@ -5257,37 +5257,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + /** + * @hide + */ @Override - public void onResolvedLayoutDirectionReset() { + public void resetResolvedLayoutDirection() { + super.resetResolvedLayoutDirection(); + // Take care of resetting the children resolution too - final int count = getChildCount(); + int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); - if (child.getLayoutDirection() == LAYOUT_DIRECTION_INHERIT) { + if (child.isLayoutDirectionInherited()) { child.resetResolvedLayoutDirection(); } - } - } - - @Override - public void onResolvedTextDirectionReset() { - // Take care of resetting the children resolution too - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getTextDirection() == TEXT_DIRECTION_INHERIT) { + if (child.isTextDirectionInherited()) { child.resetResolvedTextDirection(); } - } - } - - @Override - public void onResolvedTextAlignmentReset() { - // Take care of resetting the children resolution too - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getTextAlignment() == TEXT_ALIGNMENT_INHERIT) { + if (child.isTextAlignmentInherited()) { child.resetResolvedTextAlignment(); } } @@ -6168,7 +6155,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager view.getDrawingRect(viewLocation); root.offsetDescendantRectToMyCoords(view, viewLocation); mView = view; - mLayoutDirection = root.getResolvedLayoutDirection(); + mLayoutDirection = root.getLayoutDirection(); } private void clear() { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6bb8697..6db40ba 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -52,6 +52,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; +import android.os.UserHandle; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; import android.util.Log; @@ -1493,7 +1494,8 @@ public final class ViewRootImpl implements ViewParent, } catch (Surface.OutOfResourcesException e) { Log.e(TAG, "OutOfResourcesException initializing HW surface", e); try { - if (!mWindowSession.outOfMemory(mWindow)) { + if (!mWindowSession.outOfMemory(mWindow) && + Process.myUid() != Process.SYSTEM_UID) { Slog.w(TAG, "No processes killed for memory; killing self"); Process.killProcess(Process.myPid()); } diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 62253d3..646fe7e 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -108,7 +108,7 @@ public abstract class AbsSeekBar extends ProgressBar { if (thumb != null) { thumb.setCallback(this); if (canResolveLayoutDirection()) { - thumb.setLayoutDirection(getResolvedLayoutDirection()); + thumb.setLayoutDirection(getLayoutDirection()); } // Assuming the thumb drawable is symmetric, set the thumb offset @@ -308,6 +308,9 @@ public abstract class AbsSeekBar extends ProgressBar { thumb.setBounds(left, topBound, left + thumbWidth, bottomBound); } + /** + * @hide + */ @Override public void onResolveDrawables(int layoutDirection) { super.onResolveDrawables(layoutDirection); diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index e4d4981..75d1471 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -16,7 +16,6 @@ package android.widget; -import android.app.SearchManager.OnDismissListener; import android.content.Context; import android.content.res.TypedArray; import android.database.DataSetObserver; @@ -1094,7 +1093,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe mPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED); mPopup.setListItemExpandMax(EXPAND_MAX); } - mPopup.setLayoutDirection(getResolvedLayoutDirection()); + mPopup.setLayoutDirection(getLayoutDirection()); mPopup.show(); mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS); } diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 6ddfc3b..361eca4 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -1573,7 +1573,8 @@ public class CalendarView extends FrameLayout { // If we're showing the week number calculate it based on Monday int i = 0; if (mShowWeekNumber) { - mDayNumbers[0] = Integer.toString(mTempDate.get(Calendar.WEEK_OF_YEAR)); + mDayNumbers[0] = String.format(Locale.getDefault(), "%d", + mTempDate.get(Calendar.WEEK_OF_YEAR)); i++; } @@ -1594,7 +1595,8 @@ public class CalendarView extends FrameLayout { if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { mDayNumbers[i] = ""; } else { - mDayNumbers[i] = Integer.toString(mTempDate.get(Calendar.DAY_OF_MONTH)); + mDayNumbers[i] = String.format(Locale.getDefault(), "%d", + mTempDate.get(Calendar.DAY_OF_MONTH)); } mTempDate.add(Calendar.DAY_OF_MONTH, 1); } @@ -1658,16 +1660,34 @@ public class CalendarView extends FrameLayout { * @return True if a day was found for the given location. */ public boolean getDayFromLocation(float x, Calendar outCalendar) { - int dayStart = mShowWeekNumber ? mWidth / mNumCells : 0; - if (x < dayStart || x > mWidth) { + final boolean isLayoutRtl = isLayoutRtl(); + + int start; + int end; + + if (isLayoutRtl) { + start = 0; + end = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; + } else { + start = mShowWeekNumber ? mWidth / mNumCells : 0; + end = mWidth; + } + + if (x < start || x > end) { outCalendar.clear(); return false; } - // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels - int dayPosition = (int) ((x - dayStart) * mDaysPerWeek - / (mWidth - dayStart)); + + // Selection is (x - start) / (pixels/day) which is (x - start) * day / pixels + int dayPosition = (int) ((x - start) * mDaysPerWeek / (end - start)); + + if (isLayoutRtl) { + dayPosition = mDaysPerWeek - 1 - dayPosition; + } + outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis()); outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition); + return true; } @@ -1692,12 +1712,25 @@ public class CalendarView extends FrameLayout { mTempRect.top = mWeekSeperatorLineWidth; mTempRect.bottom = mHeight; - mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0; - mTempRect.right = mSelectedLeft - 2; + + final boolean isLayoutRtl = isLayoutRtl(); + + if (isLayoutRtl) { + mTempRect.left = 0; + mTempRect.right = mSelectedLeft - 2; + } else { + mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0; + mTempRect.right = mSelectedLeft - 2; + } canvas.drawRect(mTempRect, mDrawPaint); - mTempRect.left = mSelectedRight + 3; - mTempRect.right = mWidth; + if (isLayoutRtl) { + mTempRect.left = mSelectedRight + 3; + mTempRect.right = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; + } else { + mTempRect.left = mSelectedRight + 3; + mTempRect.right = mWidth; + } canvas.drawRect(mTempRect, mDrawPaint); } @@ -1707,25 +1740,41 @@ public class CalendarView extends FrameLayout { * @param canvas The canvas to draw on */ private void drawWeekNumbersAndDates(Canvas canvas) { - float textHeight = mDrawPaint.getTextSize(); - int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth; - int nDays = mNumCells; + final float textHeight = mDrawPaint.getTextSize(); + final int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth; + final int nDays = mNumCells; + final int divisor = 2 * nDays; mDrawPaint.setTextAlign(Align.CENTER); mDrawPaint.setTextSize(mDateTextSize); + int i = 0; - int divisor = 2 * nDays; - if (mShowWeekNumber) { - mDrawPaint.setColor(mWeekNumberColor); - int x = mWidth / divisor; - canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); - i++; - } - for (; i < nDays; i++) { - mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor - : mUnfocusedMonthDateColor); - int x = (2 * i + 1) * mWidth / divisor; - canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint); + + if (isLayoutRtl()) { + for (; i < nDays - 1; i++) { + mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor + : mUnfocusedMonthDateColor); + int x = (2 * i + 1) * mWidth / divisor; + canvas.drawText(mDayNumbers[nDays - 1 - i], x, y, mMonthNumDrawPaint); + } + if (mShowWeekNumber) { + mDrawPaint.setColor(mWeekNumberColor); + int x = mWidth - mWidth / divisor; + canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); + } + } else { + if (mShowWeekNumber) { + mDrawPaint.setColor(mWeekNumberColor); + int x = mWidth / divisor; + canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); + i++; + } + for (; i < nDays; i++) { + mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor + : mUnfocusedMonthDateColor); + int x = (2 * i + 1) * mWidth / divisor; + canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint); + } } } @@ -1745,8 +1794,16 @@ public class CalendarView extends FrameLayout { } mDrawPaint.setColor(mWeekSeparatorLineColor); mDrawPaint.setStrokeWidth(mWeekSeperatorLineWidth); - float x = mShowWeekNumber ? mWidth / mNumCells : 0; - canvas.drawLine(x, 0, mWidth, 0, mDrawPaint); + float startX; + float stopX; + if (isLayoutRtl()) { + startX = 0; + stopX = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; + } else { + startX = mShowWeekNumber ? mWidth / mNumCells : 0; + stopX = mWidth; + } + canvas.drawLine(startX, 0, stopX, 0, mDrawPaint); } /** @@ -1779,15 +1836,21 @@ public class CalendarView extends FrameLayout { */ private void updateSelectionPositions() { if (mHasSelectedDay) { + final boolean isLayoutRtl = isLayoutRtl(); int selectedPosition = mSelectedDay - mFirstDayOfWeek; if (selectedPosition < 0) { selectedPosition += 7; } - if (mShowWeekNumber) { + if (mShowWeekNumber && !isLayoutRtl) { selectedPosition++; } - mSelectedLeft = selectedPosition * mWidth / mNumCells; - mSelectedRight = (selectedPosition + 1) * mWidth / mNumCells; + if (isLayoutRtl) { + mSelectedLeft = (mDaysPerWeek - 1 - selectedPosition) * mWidth / mNumCells; + + } else { + mSelectedLeft = selectedPosition * mWidth / mNumCells; + } + mSelectedRight = mSelectedLeft + mWidth / mNumCells; } } diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index ac3bedb..07d3a7a 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -220,7 +220,7 @@ public class DatePicker extends FrameLayout { // day mDaySpinner = (NumberPicker) findViewById(R.id.day); - mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); mDaySpinner.setOnLongPressUpdateInterval(100); mDaySpinner.setOnValueChangedListener(onChangeListener); mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 237275a..c67cae6 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -88,9 +88,6 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView.OnItemClickListener; -import android.widget.Editor.InputContentType; -import android.widget.Editor.InputMethodState; -import android.widget.Editor.SelectionModifierCursorController; import android.widget.TextView.Drawables; import android.widget.TextView.OnEditorActionListener; @@ -292,7 +289,7 @@ public class Editor { mErrorWasChanged = true; final Drawables dr = mTextView.mDrawables; if (dr != null) { - switch (mTextView.getResolvedLayoutDirection()) { + switch (mTextView.getLayoutDirection()) { default: case View.LAYOUT_DIRECTION_LTR: mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index a025610..00cd604 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -411,7 +411,7 @@ public class FrameLayout extends ViewGroup { gravity = DEFAULT_CHILD_GRAVITY; } - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; @@ -483,7 +483,7 @@ public class FrameLayout extends ViewGroup { selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom); } - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), foreground.getIntrinsicHeight(), selfBounds, overlayBounds, layoutDirection); diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index b6fcb03..63147dd 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1425,7 +1425,7 @@ public class GridView extends AbsListView { int childLeft; final int childTop = flow ? y : y - h; - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index ea85325..b6f0862 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -1495,7 +1495,7 @@ public class LinearLayout extends ViewGroup { if (gravity < 0) { gravity = minorGravity; } - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.CENTER_HORIZONTAL: @@ -1559,7 +1559,7 @@ public class LinearLayout extends ViewGroup { final int[] maxAscent = mMaxAscent; final int[] maxDescent = mMaxDescent; - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) { case Gravity.RIGHT: // mTotalLength contains the padding already diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index dbc777e..704f6b6 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -51,10 +51,12 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import com.android.internal.R; +import libcore.icu.LocaleData; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * A widget that enables the user to select a number form a predefined range. @@ -138,13 +140,6 @@ public class NumberPicker extends LinearLayout { private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker; /** - * The numbers accepted by the input text's {@link Filter} - */ - private static final char[] DIGIT_CHARACTERS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' - }; - - /** * Constant for unspecified size. */ private static final int SIZE_UNSPECIFIED = -1; @@ -154,23 +149,53 @@ public class NumberPicker extends LinearLayout { * strings like "01". Keeping a static formatter etc. is the most efficient * way to do this; it avoids creating temporary objects on every call to * format(). - * - * @hide */ - public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { + private static class TwoDigitFormatter implements NumberPicker.Formatter { final StringBuilder mBuilder = new StringBuilder(); - final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); + char mZeroDigit; + java.util.Formatter mFmt; final Object[] mArgs = new Object[1]; + TwoDigitFormatter() { + final Locale locale = Locale.getDefault(); + init(locale); + } + + private void init(Locale locale) { + mFmt = createFormatter(locale); + mZeroDigit = getZeroDigit(locale); + } + public String format(int value) { + final Locale currentLocale = Locale.getDefault(); + if (mZeroDigit != getZeroDigit(currentLocale)) { + init(currentLocale); + } mArgs[0] = value; mBuilder.delete(0, mBuilder.length()); mFmt.format("%02d", mArgs); return mFmt.toString(); } - }; + + private static char getZeroDigit(Locale locale) { + return LocaleData.get(locale).zeroDigit; + } + + private java.util.Formatter createFormatter(Locale locale) { + return new java.util.Formatter(mBuilder, locale); + } + } + + private static final TwoDigitFormatter sTwoDigitFormatter = new TwoDigitFormatter(); + + /** + * @hide + */ + public static final Formatter getTwoDigitFormatter() { + return sTwoDigitFormatter; + } /** * The increment button. @@ -1156,7 +1181,7 @@ public class NumberPicker extends LinearLayout { if (mDisplayedValues == null) { float maxDigitWidth = 0; for (int i = 0; i <= 9; i++) { - final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i)); + final float digitWidth = mSelectorWheelPaint.measureText(formatNumberWithLocale(i)); if (digitWidth > maxDigitWidth) { maxDigitWidth = digitWidth; } @@ -1689,7 +1714,7 @@ public class NumberPicker extends LinearLayout { } private String formatNumber(int value) { - return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value); + return (mFormatter != null) ? mFormatter.format(value) : formatNumberWithLocale(value); } private void validateInputTextView(View v) { @@ -1849,6 +1874,20 @@ public class NumberPicker extends LinearLayout { } /** + * The numbers accepted by the input text's {@link Filter} + */ + private static final char[] DIGIT_CHARACTERS = new char[] { + // Latin digits are the common case + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + // Arabic-Indic + '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668' + , '\u0669', + // Extended Arabic-Indic + '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8' + , '\u06f9' + }; + + /** * Filter for accepting only valid indices or prefixes of the string * representation of valid indices. */ @@ -2493,4 +2532,8 @@ public class NumberPicker extends LinearLayout { return null; } } + + static private String formatNumberWithLocale(int value) { + return String.format(Locale.getDefault(), "%d", value); + } } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index b6d0995..6afaba3 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -479,7 +479,7 @@ public class ProgressBar extends View { } mIndeterminateDrawable = d; if (mIndeterminateDrawable != null && canResolveLayoutDirection()) { - mIndeterminateDrawable.setLayoutDirection(getResolvedLayoutDirection()); + mIndeterminateDrawable.setLayoutDirection(getLayoutDirection()); } if (mIndeterminate) { mCurrentDrawable = d; @@ -521,7 +521,7 @@ public class ProgressBar extends View { if (d != null) { d.setCallback(this); if (canResolveLayoutDirection()) { - d.setLayoutDirection(getResolvedLayoutDirection()); + d.setLayoutDirection(getLayoutDirection()); } // Make sure the ProgressBar is always tall enough @@ -565,6 +565,9 @@ public class ProgressBar extends View { if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState(); } + /** + * @hide + */ @Override public void onResolveDrawables(int layoutDirection) { final Drawable d = mCurrentDrawable; @@ -669,7 +672,7 @@ public class ProgressBar extends View { if (d instanceof LayerDrawable) { progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id); if (progressDrawable != null && canResolveLayoutDirection()) { - progressDrawable.setLayoutDirection(getResolvedLayoutDirection()); + progressDrawable.setLayoutDirection(getLayoutDirection()); } } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 43519df..455355f 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -483,7 +483,7 @@ public class RelativeLayout extends ViewGroup { } } - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); if (isWrapContentWidth) { // Width already has left padding in it since it was calculated by looking at @@ -578,7 +578,7 @@ public class RelativeLayout extends ViewGroup { } private void alignBaseline(View child, LayoutParams params) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); int[] rules = params.getRules(layoutDirection); int anchorBaseline = getRelatedViewBaseline(rules, ALIGN_BASELINE); @@ -727,7 +727,7 @@ public class RelativeLayout extends ViewGroup { private boolean positionChildHorizontal(View child, LayoutParams params, int myWidth, boolean wrapContent) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); int[] rules = params.getRules(layoutDirection); params.onResolveLayoutDirection(layoutDirection); @@ -792,7 +792,7 @@ public class RelativeLayout extends ViewGroup { } private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); int[] rules = childParams.getRules(layoutDirection); RelativeLayout.LayoutParams anchorParams; @@ -983,7 +983,7 @@ public class RelativeLayout extends ViewGroup { if (child.getVisibility() != GONE) { RelativeLayout.LayoutParams st = (RelativeLayout.LayoutParams) child.getLayoutParams(); - st.onResolveLayoutDirection(getResolvedLayoutDirection()); + st.onResolveLayoutDirection(getLayoutDirection()); child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom); } } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 1a47ce2..90f55bf 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -35,9 +34,9 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.LayoutInflater.Filter; import android.view.RemotableViewMethod; @@ -72,6 +71,13 @@ public class RemoteViews implements Parcelable, Filter { static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId"; /** + * User that these views should be applied as. Requires + * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} when + * crossing user boundaries. + */ + private UserHandle mUser = android.os.Process.myUserHandle(); + + /** * The package name of the package containing the layout * resource. (Added to the parcel) */ @@ -1446,11 +1452,16 @@ public class RemoteViews implements Parcelable, Filter { recalculateMemoryUsage(); } + /** {@hide} */ + public void setUser(UserHandle user) { + mUser = user; + } + private boolean hasLandscapeAndPortraitLayouts() { return (mLandscape != null) && (mPortrait != null); } - /** + /** * Create a new RemoteViews object that will inflate as the specified * landspace or portrait RemoteViews, depending on the current configuration. * @@ -2309,7 +2320,8 @@ public class RemoteViews implements Parcelable, Filter { if (packageName != null) { try { - c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED); + c = context.createPackageContextAsUser( + packageName, Context.CONTEXT_RESTRICTED, mUser); } catch (NameNotFoundException e) { Log.e(LOG_TAG, "Package name " + packageName + " not found"); c = context; diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 9b62a51..c838973 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -1354,8 +1354,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { }; @Override - public void onResolvedLayoutDirectionChanged() { - mQueryTextView.setLayoutDirection(getResolvedLayoutDirection()); + public void onRtlPropertiesChanged() { + mQueryTextView.setLayoutDirection(getLayoutDirection()); } /** diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index ecd7277..317baf1 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -492,7 +492,7 @@ public class Spinner extends AbsSpinner implements OnClickListener { View sel = makeAndAddView(mSelectedPosition); int width = sel.getMeasuredWidth(); int selectedOffset = childrenLeft; - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.CENTER_HORIZONTAL: diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java index fb548df..db3853f 100644 --- a/core/java/android/widget/TableRow.java +++ b/core/java/android/widget/TableRow.java @@ -226,7 +226,7 @@ public class TableRow extends LinearLayout { final int childWidth = child.getMeasuredWidth(); lp.mOffset[LayoutParams.LOCATION_NEXT] = columnWidth - childWidth; - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index dd2ff35..2937166 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1546,7 +1546,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public int getCompoundPaddingStart() { resolveDrawables(); - switch(getResolvedLayoutDirection()) { + switch(getLayoutDirection()) { default: case LAYOUT_DIRECTION_LTR: return getCompoundPaddingLeft(); @@ -1561,7 +1561,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public int getCompoundPaddingEnd() { resolveDrawables(); - switch(getResolvedLayoutDirection()) { + switch(getLayoutDirection()) { default: case LAYOUT_DIRECTION_LTR: return getCompoundPaddingRight(); @@ -4858,7 +4858,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isLayoutRtl = isLayoutRtl(); - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); if (mEllipsize == TextUtils.TruncateAt.MARQUEE && mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) { @@ -5635,7 +5635,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void onResolvedLayoutDirectionReset() { + public void onRtlPropertiesChanged() { if (mLayoutAlignment != null) { if (mResolvedTextAlignment == TEXT_ALIGNMENT_VIEW_START || mResolvedTextAlignment == TEXT_ALIGNMENT_VIEW_END) { @@ -5646,7 +5646,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Layout.Alignment getLayoutAlignment() { if (mLayoutAlignment == null) { - mResolvedTextAlignment = getResolvedTextAlignment(); + mResolvedTextAlignment = getTextAlignment(); switch (mResolvedTextAlignment) { case TEXT_ALIGNMENT_GRAVITY: switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) { @@ -5680,11 +5680,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mLayoutAlignment = Layout.Alignment.ALIGN_CENTER; break; case TEXT_ALIGNMENT_VIEW_START: - mLayoutAlignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ? + mLayoutAlignment = (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? Layout.Alignment.ALIGN_RIGHT : Layout.Alignment.ALIGN_LEFT; break; case TEXT_ALIGNMENT_VIEW_END: - mLayoutAlignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ? + mLayoutAlignment = (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? Layout.Alignment.ALIGN_LEFT : Layout.Alignment.ALIGN_RIGHT; break; case TEXT_ALIGNMENT_INHERIT: @@ -5733,7 +5733,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (mTextDir == null) { - resolveTextDirection(); + mTextDir = getTextDirectionHeuristic(); } mLayout = makeSingleLayout(wantWidth, boring, ellipsisWidth, alignment, shouldEllipsize, @@ -5995,7 +5995,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener BoringLayout.Metrics hintBoring = UNKNOWN_BORING; if (mTextDir == null) { - resolveTextDirection(); + getTextDirectionHeuristic(); } int des = -1; @@ -7485,7 +7485,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return 0.0f; } } else if (getLineCount() == 1) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: @@ -7512,7 +7512,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final float scroll = marquee.getScroll(); return (maxFadeScroll - scroll) / getHorizontalFadingEdgeLength(); } else if (getLineCount() == 1) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: @@ -8181,41 +8181,36 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mEditor.mInBatchEditControllers; } - @Override - public void onResolvedTextDirectionChanged() { + TextDirectionHeuristic getTextDirectionHeuristic() { if (hasPasswordTransformationMethod()) { // TODO: take care of the content direction to show the password text and dots justified // to the left or to the right - mTextDir = TextDirectionHeuristics.LOCALE; - return; + return TextDirectionHeuristics.LOCALE; } // Always need to resolve layout direction first - final boolean defaultIsRtl = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL); + final boolean defaultIsRtl = (getLayoutDirection() == LAYOUT_DIRECTION_RTL); // Now, we can select the heuristic - int textDir = getResolvedTextDirection(); - switch (textDir) { + switch (getTextDirection()) { default: case TEXT_DIRECTION_FIRST_STRONG: - mTextDir = (defaultIsRtl ? TextDirectionHeuristics.FIRSTSTRONG_RTL : + return (defaultIsRtl ? TextDirectionHeuristics.FIRSTSTRONG_RTL : TextDirectionHeuristics.FIRSTSTRONG_LTR); - break; case TEXT_DIRECTION_ANY_RTL: - mTextDir = TextDirectionHeuristics.ANYRTL_LTR; - break; + return TextDirectionHeuristics.ANYRTL_LTR; case TEXT_DIRECTION_LTR: - mTextDir = TextDirectionHeuristics.LTR; - break; + return TextDirectionHeuristics.LTR; case TEXT_DIRECTION_RTL: - mTextDir = TextDirectionHeuristics.RTL; - break; + return TextDirectionHeuristics.RTL; case TEXT_DIRECTION_LOCALE: - mTextDir = TextDirectionHeuristics.LOCALE; - break; + return TextDirectionHeuristics.LOCALE; } } + /** + * @hide + */ @Override public void onResolveDrawables(int layoutDirection) { // No need to resolve twice diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index cb9ed61..e6796cb 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -172,7 +172,7 @@ public class TimePicker extends FrameLayout { mMinuteSpinner.setMinValue(0); mMinuteSpinner.setMaxValue(59); mMinuteSpinner.setOnLongPressUpdateInterval(100); - mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { updateInputState(); @@ -500,7 +500,7 @@ public class TimePicker extends FrameLayout { if (is24HourView()) { mHourSpinner.setMinValue(0); mHourSpinner.setMaxValue(23); - mHourSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + mHourSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); } else { mHourSpinner.setMinValue(1); mHourSpinner.setMaxValue(12); diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java index cb87ac4..a91aa3c 100644 --- a/core/java/com/android/internal/statusbar/StatusBarNotification.java +++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java @@ -20,8 +20,6 @@ import android.app.Notification; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; -import android.widget.RemoteViews; - /* boolean clearable = !n.ongoingEvent && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0); @@ -39,19 +37,26 @@ if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) { * Class encapsulating a Notification. Sent by the NotificationManagerService to the IStatusBar (in System UI). */ public class StatusBarNotification implements Parcelable { - public String pkg; - public int id; - public String tag; - public int uid; - public int initialPid; - public Notification notification; - public int score; - - public StatusBarNotification() { + public final String pkg; + public final int id; + public final String tag; + public final int uid; + public final int initialPid; + // TODO: make this field private and move callers to an accessor that + // ensures sourceUser is applied. + public final Notification notification; + public final int score; + public final UserHandle user; + + /** This is temporarily needed for the JB MR1 PDK. */ + @Deprecated + public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score, + Notification notification) { + this(pkg, id, tag, uid, initialPid, score, notification, UserHandle.OWNER); } - public StatusBarNotification(String pkg, int id, String tag, - int uid, int initialPid, int score, Notification notification) { + public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score, + Notification notification, UserHandle user) { if (pkg == null) throw new NullPointerException(); if (notification == null) throw new NullPointerException(); @@ -62,13 +67,11 @@ public class StatusBarNotification implements Parcelable { this.initialPid = initialPid; this.score = score; this.notification = notification; + this.user = user; + this.notification.setUser(user); } public StatusBarNotification(Parcel in) { - readFromParcel(in); - } - - public void readFromParcel(Parcel in) { this.pkg = in.readString(); this.id = in.readInt(); if (in.readInt() != 0) { @@ -80,6 +83,8 @@ public class StatusBarNotification implements Parcelable { this.initialPid = in.readInt(); this.score = in.readInt(); this.notification = new Notification(in); + this.user = UserHandle.readFromParcel(in); + this.notification.setUser(user); } public void writeToParcel(Parcel out, int flags) { @@ -95,6 +100,7 @@ public class StatusBarNotification implements Parcelable { out.writeInt(this.initialPid); out.writeInt(this.score); this.notification.writeToParcel(out, flags); + user.writeToParcel(out, flags); } public int describeContents() { @@ -115,14 +121,16 @@ public class StatusBarNotification implements Parcelable { } }; + @Override public StatusBarNotification clone() { - return new StatusBarNotification(this.pkg, this.id, this.tag, - this.uid, this.initialPid, this.score, this.notification.clone()); + return new StatusBarNotification(this.pkg, this.id, this.tag, this.uid, this.initialPid, + this.score, this.notification.clone(), this.user); } + @Override public String toString() { - return "StatusBarNotification(pkg=" + pkg + " id=" + id + " tag=" + tag - + " score=" + score + " notn=" + notification + ")"; + return "StatusBarNotification(pkg=" + pkg + " id=" + id + " tag=" + tag + " score=" + score + + " notn=" + notification + " user=" + user + ")"; } public boolean isOngoing() { @@ -136,8 +144,6 @@ public class StatusBarNotification implements Parcelable { /** Returns a userHandle for the instance of the app that posted this notification. */ public int getUserId() { - return UserHandle.getUserId(this.uid); + return this.user.getIdentifier(); } } - - diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index c7c8571..5d0b25f 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -281,7 +281,7 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie Rect tmpRect = mPositionIconOutput; getLineBounds(0, tmpRect); mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top); - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.START, mIcon.getIntrinsicWidth(), mIcon .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput, layoutDirection); diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java index 6bcaa0e..0cfe4fd 100644 --- a/core/java/com/android/internal/widget/ActionBarContainer.java +++ b/core/java/com/android/internal/widget/ActionBarContainer.java @@ -161,6 +161,9 @@ public class ActionBarContainer extends FrameLayout { } } + /** + * @hide + */ @Override public void onResolveDrawables(int layoutDirection) { super.onResolveDrawables(layoutDirection); diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 2108d0d..4715750 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -1088,7 +1088,7 @@ public class ActionBarView extends AbsActionBarView { customView = mCustomNavView; } if (customView != null) { - final int resolvedLayoutDirection = getResolvedLayoutDirection(); + final int resolvedLayoutDirection = getLayoutDirection(); ViewGroup.LayoutParams lp = customView.getLayoutParams(); lp.onResolveLayoutDirection(resolvedLayoutDirection); final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ? @@ -1372,7 +1372,7 @@ public class ActionBarView extends AbsActionBarView { protected void onLayout(boolean changed, int l, int t, int r, int b) { final int vCenter = (b - t) / 2; final boolean isLayoutRtl = isLayoutRtl(); - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int width = getWidth(); int upOffset = 0; if (mUpView.getVisibility() != GONE) { diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java index 421e247..549d74c 100644 --- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java +++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java @@ -39,7 +39,6 @@ import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import com.android.internal.R; @@ -197,6 +196,7 @@ public class GlowPadView extends View { private Tweener mBackgroundAnimator; private PointCloud mPointCloud; private float mInnerRadius; + private int mPointerId; public GlowPadView(Context context) { this(context, null); @@ -737,9 +737,10 @@ public class GlowPadView extends View { @Override public boolean onTouchEvent(MotionEvent event) { - final int action = event.getAction(); + final int action = event.getActionMasked(); boolean handled = false; switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_DOWN: if (DEBUG) Log.v(TAG, "*** DOWN ***"); handleDown(event); @@ -753,6 +754,7 @@ public class GlowPadView extends View { handled = true; break; + case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_UP: if (DEBUG) Log.v(TAG, "*** UP ***"); handleMove(event); @@ -766,6 +768,7 @@ public class GlowPadView extends View { handleCancel(event); handled = true; break; + } invalidate(); return handled ? true : super.onTouchEvent(event); @@ -777,19 +780,24 @@ public class GlowPadView extends View { } private void handleDown(MotionEvent event) { - float eventX = event.getX(); - float eventY = event.getY(); + int actionIndex = event.getActionIndex(); + float eventX = event.getX(actionIndex); + float eventY = event.getY(actionIndex); switchToState(STATE_START, eventX, eventY); if (!trySwitchToFirstTouchState(eventX, eventY)) { mDragging = false; } else { + mPointerId = event.getPointerId(actionIndex); updateGlowPosition(eventX, eventY); } } private void handleUp(MotionEvent event) { if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE"); - switchToState(STATE_FINISH, event.getX(), event.getY()); + int actionIndex = event.getActionIndex(); + if (event.getPointerId(actionIndex) == mPointerId) { + switchToState(STATE_FINISH, event.getX(actionIndex), event.getY(actionIndex)); + } } private void handleCancel(MotionEvent event) { @@ -802,7 +810,9 @@ public class GlowPadView extends View { // mActiveTarget = -1; // Drop the active target if canceled. - switchToState(STATE_FINISH, event.getX(), event.getY()); + int actionIndex = event.findPointerIndex(mPointerId); + actionIndex = actionIndex == -1 ? 0 : actionIndex; + switchToState(STATE_FINISH, event.getX(actionIndex), event.getY(actionIndex)); } private void handleMove(MotionEvent event) { @@ -812,9 +822,17 @@ public class GlowPadView extends View { int ntargets = targets.size(); float x = 0.0f; float y = 0.0f; + int actionIndex = event.findPointerIndex(mPointerId); + + if (actionIndex == -1) { + return; // no data for this pointer + } + for (int k = 0; k < historySize + 1; k++) { - float eventX = k < historySize ? event.getHistoricalX(k) : event.getX(); - float eventY = k < historySize ? event.getHistoricalY(k) : event.getY(); + float eventX = k < historySize ? event.getHistoricalX(actionIndex, k) + : event.getX(actionIndex); + float eventY = k < historySize ? event.getHistoricalY(actionIndex, k) + : event.getY(actionIndex); // tx and ty are relative to wave center float tx = eventX - mWaveCenterX; float ty = eventY - mWaveCenterY; @@ -957,7 +975,7 @@ public class GlowPadView extends View { } private void computeInsets(int dx, int dy) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java index 10804c0..7990b4c 100644 --- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -19,7 +19,6 @@ package com.android.internal.widget.multiwaveview; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; @@ -970,7 +969,7 @@ public class MultiWaveView extends View { } private void computeInsets(int dx, int dy) { - final int layoutDirection = getResolvedLayoutDirection(); + final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { |