summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityManagerNative.java52
-rw-r--r--core/java/android/app/ActivityOptions.java4
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java6
-rw-r--r--core/java/android/app/ContextImpl.java33
-rw-r--r--core/java/android/app/IActivityManager.java24
-rw-r--r--core/java/android/app/LauncherActivity.java12
-rw-r--r--core/java/android/content/ClipData.java21
-rw-r--r--core/java/android/content/ContentProvider.java114
-rw-r--r--core/java/android/content/ContentProviderOperation.java27
-rw-r--r--core/java/android/content/ContentProviderResult.java10
-rw-r--r--core/java/android/content/ContentResolver.java11
-rw-r--r--core/java/android/content/Intent.java36
-rw-r--r--core/java/android/transition/Transition.java610
-rw-r--r--core/java/android/transition/TransitionInflater.java9
-rw-r--r--core/java/android/transition/TransitionSet.java30
-rw-r--r--core/java/android/transition/TransitionValuesMaps.java6
-rw-r--r--core/java/android/transition/Visibility.java29
-rw-r--r--core/java/android/view/ThreadedRenderer.java45
-rw-r--r--core/java/android/view/View.java50
-rw-r--r--core/java/android/view/ViewGroup.java10
20 files changed, 779 insertions, 360 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ec2868a..296e9d3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1114,7 +1114,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
int pid = data.readInt();
int uid = data.readInt();
int mode = data.readInt();
- int res = checkUriPermission(uri, pid, uid, mode);
+ int userId = data.readInt();
+ int res = checkUriPermission(uri, pid, uid, mode, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -1139,7 +1140,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
String targetPkg = data.readString();
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- grantUriPermission(app, targetPkg, uri, mode);
+ int userId = data.readInt();
+ grantUriPermission(app, targetPkg, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1150,7 +1152,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- revokeUriPermission(app, uri, mode);
+ int userId = data.readInt();
+ revokeUriPermission(app, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1159,7 +1162,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
data.enforceInterface(IActivityManager.descriptor);
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- takePersistableUriPermission(uri, mode);
+ int userId = data.readInt();
+ takePersistableUriPermission(uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1168,7 +1172,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
data.enforceInterface(IActivityManager.descriptor);
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- releasePersistableUriPermission(uri, mode);
+ int userId = data.readInt();
+ releasePersistableUriPermission(uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1602,7 +1607,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
String targetPkg = data.readString();
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode);
+ int userId = data.readInt();
+ grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1612,10 +1618,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
IBinder owner = data.readStrongBinder();
Uri uri = null;
if (data.readInt() != 0) {
- Uri.CREATOR.createFromParcel(data);
+ uri = Uri.CREATOR.createFromParcel(data);
}
int mode = data.readInt();
- revokeUriPermissionFromOwner(owner, uri, mode);
+ int userId = data.readInt();
+ revokeUriPermissionFromOwner(owner, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1626,7 +1633,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
String targetPkg = data.readString();
Uri uri = Uri.CREATOR.createFromParcel(data);
int modeFlags = data.readInt();
- int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags);
+ int userId = data.readInt();
+ int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -3540,7 +3548,7 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
- public int checkUriPermission(Uri uri, int pid, int uid, int mode)
+ public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -3549,6 +3557,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeInt(pid);
data.writeInt(uid);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
@@ -3557,7 +3566,7 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, int mode) throws RemoteException {
+ Uri uri, int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3565,19 +3574,21 @@ class ActivityManagerProxy implements IActivityManager
data.writeString(targetPkg);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public void revokeUriPermission(IApplicationThread caller, Uri uri,
- int mode) throws RemoteException {
+ int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller.asBinder());
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -3585,12 +3596,14 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
- public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+ public void takePersistableUriPermission(Uri uri, int mode, int userId)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -3598,12 +3611,14 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
- public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+ public void releasePersistableUriPermission(Uri uri, int mode, int userId)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4157,7 +4172,7 @@ class ActivityManagerProxy implements IActivityManager
}
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
- Uri uri, int mode) throws RemoteException {
+ Uri uri, int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4166,6 +4181,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeString(targetPkg);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4173,7 +4189,7 @@ class ActivityManagerProxy implements IActivityManager
}
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
- int mode) throws RemoteException {
+ int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4185,6 +4201,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeInt(0);
}
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4192,7 +4209,7 @@ class ActivityManagerProxy implements IActivityManager
}
public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, int modeFlags) throws RemoteException {
+ Uri uri, int modeFlags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4200,6 +4217,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeString(targetPkg);
uri.writeToParcel(data, 0);
data.writeInt(modeFlags);
+ data.writeInt(userId);
mRemote.transact(CHECK_GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a49359f..692efd7 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -365,11 +365,15 @@ public class ActivityOptions {
* @param listener The listener to use to monitor activity transition events.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
+ * Returns null if the Window does not have {@link Window#FEATURE_CONTENT_TRANSITIONS}.
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
public static ActivityOptions makeSceneTransitionAnimation(Window window,
ActivityTransitionListener listener) {
+ if (!window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+ return null;
+ }
ActivityOptions opts = new ActivityOptions();
opts.mAnimationType = ANIM_SCENE_TRANSITION;
ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 3eb2fea..ca64788 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -472,7 +472,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
if (getViewsTransition() != null) {
setViewVisibility(mEnteringViews, View.VISIBLE);
}
- getDecor().findSharedElements(map);
+ getDecor().findNamedViews(map);
if (getViewsTransition() != null) {
setViewVisibility(mEnteringViews, View.INVISIBLE);
}
@@ -712,7 +712,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
- sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
+ sharedElementBundle.putString(KEY_NAME, view.getViewName());
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
@@ -882,7 +882,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
imageView.setId(com.android.internal.R.id.shared_element);
imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setImageBitmap(bitmap);
- imageView.setSharedElementName(name);
+ imageView.setViewName(name);
setSharedElementState(imageView, name, state, parentLoc);
if (mTargetSharedNames.contains(name)) {
accepted.add(imageView);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 801182d..b4d8942 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -26,6 +26,7 @@ import com.android.internal.util.Preconditions;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -1818,8 +1819,8 @@ class ContextImpl extends Context {
public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
try {
ActivityManagerNative.getDefault().grantUriPermission(
- mMainThread.getApplicationThread(), toPackage, uri,
- modeFlags);
+ mMainThread.getApplicationThread(), toPackage,
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -1828,8 +1829,8 @@ class ContextImpl extends Context {
public void revokeUriPermission(Uri uri, int modeFlags) {
try {
ActivityManagerNative.getDefault().revokeUriPermission(
- mMainThread.getApplicationThread(), uri,
- modeFlags);
+ mMainThread.getApplicationThread(),
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -1838,12 +1839,17 @@ class ContextImpl extends Context {
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
try {
return ActivityManagerNative.getDefault().checkUriPermission(
- uri, pid, uid, modeFlags);
+ ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
+ resolveUserId(uri));
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
}
}
+ private int resolveUserId(Uri uri) {
+ return ContentProvider.getUserIdFromUri(uri, getUserId());
+ }
+
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
int pid = Binder.getCallingPid();
@@ -2280,12 +2286,16 @@ class ContextImpl extends Context {
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
- return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);
+ return mMainThread.acquireProvider(context,
+ ContentProvider.getAuthorityWithoutUserId(auth),
+ resolveUserIdFromAuthority(auth), true);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
- return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true);
+ return mMainThread.acquireExistingProvider(context,
+ ContentProvider.getAuthorityWithoutUserId(auth),
+ resolveUserIdFromAuthority(auth), true);
}
@Override
@@ -2295,7 +2305,9 @@ class ContextImpl extends Context {
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
- return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
+ return mMainThread.acquireProvider(c,
+ ContentProvider.getAuthorityWithoutUserId(auth),
+ resolveUserIdFromAuthority(auth), false);
}
@Override
@@ -2312,5 +2324,10 @@ class ContextImpl extends Context {
public void appNotRespondingViaProvider(IContentProvider icp) {
mMainThread.appNotRespondingViaProvider(icp.asBinder());
}
+
+ /** @hide */
+ protected int resolveUserIdFromAuthority(String auth) {
+ return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());
+ }
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 074b427..a30a64a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -210,14 +210,16 @@ public interface IActivityManager extends IInterface {
public int checkPermission(String permission, int pid, int uid)
throws RemoteException;
- public int checkUriPermission(Uri uri, int pid, int uid, int mode)
+ public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
+ throws RemoteException;
+ public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
+ int mode, int userId) throws RemoteException;
+ public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId)
+ throws RemoteException;
+ public void takePersistableUriPermission(Uri uri, int modeFlags, int userId)
+ throws RemoteException;
+ public void releasePersistableUriPermission(Uri uri, int modeFlags, int userId)
throws RemoteException;
- public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, int mode) throws RemoteException;
- public void revokeUriPermission(IApplicationThread caller, Uri uri,
- int mode) throws RemoteException;
- public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
- public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
public ParceledListSlice<UriPermission> getPersistedUriPermissions(
String packageName, boolean incoming) throws RemoteException;
@@ -323,12 +325,12 @@ public interface IActivityManager extends IInterface {
public IBinder newUriPermissionOwner(String name) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
- Uri uri, int mode) throws RemoteException;
+ Uri uri, int mode, int userId) throws RemoteException;
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
- int mode) throws RemoteException;
+ int mode, int userId) throws RemoteException;
- public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, int modeFlags) throws RemoteException;
+ public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
+ int modeFlags, int userId) throws RemoteException;
// Cause the specified process to dump the specified heap.
public boolean dumpHeap(String process, int userId, boolean managed, String path,
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 96c7246..9ec7f41 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -340,9 +340,11 @@ public abstract class LauncherActivity extends ListActivity {
super.onCreate(icicle);
mPackageManager = getPackageManager();
-
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setProgressBarIndeterminateVisibility(true);
+
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setProgressBarIndeterminateVisibility(true);
+ }
onSetContentView();
mIconResizer = new IconResizer();
@@ -357,7 +359,9 @@ public abstract class LauncherActivity extends ListActivity {
updateAlertTitle();
updateButtonText();
- setProgressBarIndeterminateVisibility(false);
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ setProgressBarIndeterminateVisibility(false);
+ }
}
private void updateAlertTitle() {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 50c4fed..b44abf9 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -16,6 +16,7 @@
package android.content;
+import static android.content.ContentProvider.maybeAddUserId;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -186,7 +187,7 @@ public class ClipData implements Parcelable {
final CharSequence mText;
final String mHtmlText;
final Intent mIntent;
- final Uri mUri;
+ Uri mUri;
/**
* Create an Item consisting of a single block of (possibly styled) text.
@@ -809,6 +810,24 @@ public class ClipData implements Parcelable {
}
}
+ /**
+ * Prepare this {@link ClipData} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveUser(int userId) {
+ final int size = mItems.size();
+ for (int i = 0; i < size; i++) {
+ final Item item = mItems.get(i);
+ if (item.mIntent != null) {
+ item.mIntent.prepareToLeaveUser(userId);
+ }
+ if (item.mUri != null) {
+ item.mUri = maybeAddUserId(item.mUri, userId);
+ }
+ }
+ }
+
@Override
public String toString() {
StringBuilder b = new StringBuilder(128);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 02c850b..be9782f 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -36,6 +36,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.text.TextUtils;
import java.io.File;
import java.io.FileDescriptor;
@@ -195,6 +196,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
@@ -207,6 +209,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public String getType(Uri uri) {
+ uri = getUriWithoutUserId(uri);
return ContentProvider.this.getType(uri);
}
@@ -215,9 +218,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
+ int userId = getUserIdFromUri(uri);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.insert(uri, initialValues);
+ return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId);
} finally {
setCallingPackage(original);
}
@@ -228,6 +233,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.bulkInsert(uri, initialValues);
@@ -240,24 +246,39 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public ContentProviderResult[] applyBatch(String callingPkg,
ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
- for (ContentProviderOperation operation : operations) {
+ int numOperations = operations.size();
+ final int[] userIds = new int[numOperations];
+ for (int i = 0; i < numOperations; i++) {
+ ContentProviderOperation operation = operations.get(i);
+ userIds[i] = getUserIdFromUri(operation.getUri());
if (operation.isReadOperation()) {
if (enforceReadPermission(callingPkg, operation.getUri())
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
-
if (operation.isWriteOperation()) {
if (enforceWritePermission(callingPkg, operation.getUri())
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
+ if (userIds[i] != UserHandle.USER_CURRENT) {
+ // Removing the user id from the uri.
+ operation = new ContentProviderOperation(operation, true);
+ }
+ operations.set(i, operation);
}
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.applyBatch(operations);
+ ContentProviderResult[] results = ContentProvider.this.applyBatch(operations);
+ for (int i = 0; i < results.length ; i++) {
+ if (userIds[i] != UserHandle.USER_CURRENT) {
+ // Adding the userId to the uri.
+ results[i] = new ContentProviderResult(results[i], userIds[i]);
+ }
+ }
+ return results;
} finally {
setCallingPackage(original);
}
@@ -268,6 +289,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.delete(uri, selection, selectionArgs);
@@ -282,6 +304,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.update(uri, values, selection, selectionArgs);
@@ -295,6 +318,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openFile(
@@ -309,6 +333,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openAssetFile(
@@ -330,6 +355,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+ uri = getUriWithoutUserId(uri);
return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
}
@@ -337,6 +363,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r");
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openTypedAssetFile(
@@ -356,9 +383,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
+ int userId = getUserIdFromUri(uri);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.canonicalize(uri);
+ return maybeAddUserId(ContentProvider.this.canonicalize(uri), userId);
} finally {
setCallingPackage(original);
}
@@ -369,9 +398,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
+ int userId = getUserIdFromUri(uri);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.uncanonicalize(uri);
+ return maybeAddUserId(ContentProvider.this.uncanonicalize(uri), userId);
} finally {
setCallingPackage(original);
}
@@ -1680,4 +1711,75 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("nothing to dump");
}
+
+ /** @hide */
+ public static int getUserIdFromAuthority(String auth, int defaultUserId) {
+ if (auth == null) return defaultUserId;
+ int end = auth.indexOf('@');
+ if (end == -1) return defaultUserId;
+ String userIdString = auth.substring(0, end);
+ try {
+ return Integer.parseInt(userIdString);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing userId.", e);
+ return UserHandle.USER_NULL;
+ }
+ }
+
+ /** @hide */
+ public static int getUserIdFromAuthority(String auth) {
+ return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
+ }
+
+ /** @hide */
+ public static int getUserIdFromUri(Uri uri, int defaultUserId) {
+ if (uri == null) return defaultUserId;
+ return getUserIdFromAuthority(uri.getAuthority(), defaultUserId);
+ }
+
+ /** @hide */
+ public static int getUserIdFromUri(Uri uri) {
+ return getUserIdFromUri(uri, UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Removes userId part from authority string. Expects format:
+ * userId@some.authority
+ * If there is no userId in the authority, it symply returns the argument
+ * @hide
+ */
+ public static String getAuthorityWithoutUserId(String auth) {
+ if (auth == null) return null;
+ int end = auth.indexOf('@');
+ return auth.substring(end+1);
+ }
+
+ /** @hide */
+ public static Uri getUriWithoutUserId(Uri uri) {
+ if (uri == null) return null;
+ Uri.Builder builder = uri.buildUpon();
+ builder.authority(getAuthorityWithoutUserId(uri.getAuthority()));
+ return builder.build();
+ }
+
+ /** @hide */
+ public static boolean uriHasUserId(Uri uri) {
+ if (uri == null) return false;
+ return !TextUtils.isEmpty(uri.getUserInfo());
+ }
+
+ /** @hide */
+ public static Uri maybeAddUserId(Uri uri, int userId) {
+ if (uri == null) return null;
+ if (userId != UserHandle.USER_CURRENT
+ && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ if (!uriHasUserId(uri)) {
+ //We don't add the user Id if there's already one
+ Uri.Builder builder = uri.buildUpon();
+ builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority());
+ return builder.build();
+ }
+ }
+ return uri;
+ }
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 12e9bab..136e54d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -16,6 +16,7 @@
package android.content;
+import android.content.ContentProvider;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
@@ -87,6 +88,31 @@ public class ContentProviderOperation implements Parcelable {
mYieldAllowed = source.readInt() != 0;
}
+ /** @hide */
+ public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) {
+ mType = cpo.mType;
+ if (removeUserIdFromUri) {
+ mUri = ContentProvider.getUriWithoutUserId(cpo.mUri);
+ } else {
+ mUri = cpo.mUri;
+ }
+ mValues = cpo.mValues;
+ mSelection = cpo.mSelection;
+ mSelectionArgs = cpo.mSelectionArgs;
+ mExpectedCount = cpo.mExpectedCount;
+ mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences;
+ mValuesBackReferences = cpo.mValuesBackReferences;
+ mYieldAllowed = cpo.mYieldAllowed;
+ }
+
+ /** @hide */
+ public ContentProviderOperation getWithoutUserIdInUri() {
+ if (ContentProvider.uriHasUserId(mUri)) {
+ return new ContentProviderOperation(this, true);
+ }
+ return this;
+ }
+
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
Uri.writeToParcel(dest, mUri);
@@ -387,7 +413,6 @@ public class ContentProviderOperation implements Parcelable {
}
};
-
/**
* Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
* first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index 5d188ef..ec3d002 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -16,7 +16,9 @@
package android.content;
+import android.content.ContentProvider;
import android.net.Uri;
+import android.os.UserHandle;
import android.os.Parcelable;
import android.os.Parcel;
@@ -50,6 +52,12 @@ public class ContentProviderResult implements Parcelable {
}
}
+ /** @hide */
+ public ContentProviderResult(ContentProviderResult cpr, int userId) {
+ uri = ContentProvider.maybeAddUserId(cpr.uri, userId);
+ count = cpr.count;
+ }
+
public void writeToParcel(Parcel dest, int flags) {
if (uri == null) {
dest.writeInt(1);
@@ -81,4 +89,4 @@ public class ContentProviderResult implements Parcelable {
}
return "ContentProviderResult(count=" + count + ")";
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 5b41394..7642e13 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1643,7 +1643,8 @@ public abstract class ContentResolver {
*/
public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
try {
- ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
+ ActivityManagerNative.getDefault().takePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -1658,7 +1659,8 @@ public abstract class ContentResolver {
*/
public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
try {
- ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
+ ActivityManagerNative.getDefault().releasePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -2462,4 +2464,9 @@ public abstract class ContentResolver {
private final Context mContext;
final String mPackageName;
private static final String TAG = "ContentResolver";
+
+ /** @hide */
+ public int resolveUserId(Uri uri) {
+ return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
+ }
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3cfc56c..076f657 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -26,6 +26,7 @@ import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.pm.ActivityInfo;
+import static android.content.ContentProvider.maybeAddUserId;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -7433,6 +7434,41 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Prepare this {@link Intent} to be sent to another user
+ *
+ * @hide
+ */
+ public void prepareToLeaveUser(int userId) {
+ Uri data = getData();
+ if (data != null) {
+ mData = maybeAddUserId(data, userId);
+ }
+ if (mSelector != null) {
+ mSelector.prepareToLeaveUser(userId);
+ }
+ if (mClipData != null) {
+ mClipData.prepareToLeaveUser(userId);
+ }
+ String action = getAction();
+ if (ACTION_SEND.equals(action)) {
+ final Uri stream = getParcelableExtra(EXTRA_STREAM);
+ if (stream != null) {
+ putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId));
+ }
+ }
+ if (ACTION_SEND_MULTIPLE.equals(action)) {
+ final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
+ if (streams != null) {
+ ArrayList<Uri> newStreams = new ArrayList<Uri>();
+ for (int i = 0; i < streams.size(); i++) {
+ newStreams.add(maybeAddUserId(streams.get(i), userId));
+ }
+ putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
+ }
+ }
+ }
+
+ /**
* Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
* {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
* intents in {@link #ACTION_CHOOSER}.
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 49a0138..5a432dc 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -24,6 +24,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -89,7 +90,8 @@ import java.util.List;
* out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
* takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
* of which lists a specific <code>targetId</code>, <code>targetClass</code>,
- * <code>excludeId</code>, or <code>excludeClass</code>, which this transition acts upon.
+ * <code>targetViewName</code>, <code>excludeId</code>, <code>excludeClass</code>, or
+ * <code>excludeViewName</code>, which this transition acts upon.
* Use of targets is optional, but can be used to either limit the time spent checking
* attributes on unchanging views, or limiting the types of animations run on specific views.
* In this case, we know that only the <code>grayscaleContainer</code> will be
@@ -113,10 +115,12 @@ public abstract class Transition implements Cloneable {
TimeInterpolator mInterpolator = null;
ArrayList<Integer> mTargetIds = new ArrayList<Integer>();
ArrayList<View> mTargets = new ArrayList<View>();
+ ArrayList<String> mTargetNames = null;
+ ArrayList<Class> mTargetTypes = null;
ArrayList<Integer> mTargetIdExcludes = null;
ArrayList<View> mTargetExcludes = null;
ArrayList<Class> mTargetTypeExcludes = null;
- ArrayList<Class> mTargetTypes = null;
+ ArrayList<String> mTargetNameExcludes = null;
ArrayList<Integer> mTargetIdChildExcludes = null;
ArrayList<View> mTargetChildExcludes = null;
ArrayList<Class> mTargetTypeChildExcludes = null;
@@ -334,6 +338,133 @@ public abstract class Transition implements Cloneable {
}
/**
+ * Match start/end values by View instance. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd.
+ */
+ private void matchInstances(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd) {
+ for (int i = unmatchedStart.size() - 1; i >= 0; i--) {
+ View view = unmatchedStart.keyAt(i);
+ TransitionValues end = unmatchedEnd.remove(view);
+ if (end != null) {
+ TransitionValues start = unmatchedStart.removeAt(i);
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ }
+ }
+
+ /**
+ * Match start/end values by Adapter item ID. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+ * startItemIds and endItemIds as a guide for which Views have unique item IDs.
+ */
+ private void matchItemIds(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd,
+ LongSparseArray<View> startItemIds, LongSparseArray<View> endItemIds) {
+ int numStartIds = startItemIds.size();
+ for (int i = 0; i < numStartIds; i++) {
+ View startView = startItemIds.valueAt(i);
+ if (startView != null) {
+ View endView = endItemIds.get(startItemIds.keyAt(i));
+ if (endView != null) {
+ TransitionValues startValues = unmatchedStart.get(startView);
+ TransitionValues endValues = unmatchedEnd.get(endView);
+ if (startValues != null && endValues != null) {
+ startValuesList.add(startValues);
+ endValuesList.add(endValues);
+ unmatchedStart.remove(startView);
+ unmatchedEnd.remove(endView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Match start/end values by Adapter view ID. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+ * startIds and endIds as a guide for which Views have unique IDs.
+ */
+ private void matchIds(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd,
+ SparseArray<View> startIds, SparseArray<View> endIds) {
+ int numStartIds = startIds.size();
+ for (int i = 0; i < numStartIds; i++) {
+ View startView = startIds.valueAt(i);
+ if (startView != null && isValidTarget(startView)) {
+ View endView = endIds.get(startIds.keyAt(i));
+ if (endView != null && isValidTarget(endView)) {
+ TransitionValues startValues = unmatchedStart.get(startView);
+ TransitionValues endValues = unmatchedEnd.get(endView);
+ if (startValues != null && endValues != null) {
+ startValuesList.add(startValues);
+ endValuesList.add(endValues);
+ unmatchedStart.remove(startView);
+ unmatchedEnd.remove(endView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Match start/end values by Adapter viewName. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+ * startNames and endNames as a guide for which Views have unique viewNames.
+ */
+ private void matchNames(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd,
+ ArrayMap<String, View> startNames, ArrayMap<String, View> endNames) {
+ int numStartNames = startNames.size();
+ for (int i = 0; i < numStartNames; i++) {
+ View startView = startNames.valueAt(i);
+ if (startView != null && isValidTarget(startView)) {
+ View endView = endNames.get(startNames.keyAt(i));
+ if (endView != null && isValidTarget(endView)) {
+ TransitionValues startValues = unmatchedStart.get(startView);
+ TransitionValues endValues = unmatchedEnd.get(endView);
+ if (startValues != null && endValues != null) {
+ startValuesList.add(startValues);
+ endValuesList.add(endValues);
+ unmatchedStart.remove(startView);
+ unmatchedEnd.remove(endView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds all values from unmatchedStart and unmatchedEnd to startValuesList and endValuesList,
+ * assuming that there is no match between values in the list.
+ */
+ private void addUnmatched(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd) {
+ // Views that only exist in the start Scene
+ for (int i = 0; i < unmatchedStart.size(); i++) {
+ startValuesList.add(unmatchedStart.valueAt(i));
+ endValuesList.add(null);
+ }
+
+ // Views that only exist in the end Scene
+ for (int i = 0; i < unmatchedEnd.size(); i++) {
+ endValuesList.add(unmatchedEnd.valueAt(i));
+ startValuesList.add(null);
+ }
+ }
+
+ /**
* This method, essentially a wrapper around all calls to createAnimator for all
* possible target views, is called with the entire set of start/end
* values. The implementation in Transition iterates through these lists
@@ -349,76 +480,22 @@ public abstract class Transition implements Cloneable {
if (DBG) {
Log.d(LOG_TAG, "createAnimators() for " + this);
}
- ArrayMap<View, TransitionValues> endCopy =
+ ArrayMap<View, TransitionValues> unmatchedStart =
+ new ArrayMap<View, TransitionValues>(startValues.viewValues);
+ ArrayMap<View, TransitionValues> unmatchedEnd =
new ArrayMap<View, TransitionValues>(endValues.viewValues);
- SparseArray<TransitionValues> endIdCopy = endValues.idValues.clone();
- LongSparseArray<TransitionValues> endItemIdCopy = endValues.itemIdValues.clone();
- // Walk through the start values, playing everything we find
- // Remove from the end set as we go
+
ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
- for (View view : startValues.viewValues.keySet()) {
- TransitionValues start = null;
- TransitionValues end = null;
- boolean isInListView = false;
- if (view.getParent() instanceof ListView) {
- isInListView = true;
- }
- if (!isInListView) {
- int id = view.getId();
- start = startValues.viewValues.get(view);
- end = endValues.viewValues.get(view);
- if (end != null) {
- endCopy.remove(view);
- } else if (id != View.NO_ID) {
- end = endIdCopy.get(id);
- if (end == null || startValues.viewValues.containsKey(end.view)) {
- end = null;
- id = View.NO_ID;
- } else {
- endCopy.remove(end.view);
- }
- }
- endIdCopy.remove(id);
- if (isValidTarget(view, id)) {
- startValuesList.add(start);
- endValuesList.add(end);
- }
- } else {
- ListView parent = (ListView) view.getParent();
- if (parent.getAdapter().hasStableIds()) {
- int position = parent.getPositionForView(view);
- long itemId = parent.getItemIdAtPosition(position);
- start = startValues.itemIdValues.get(itemId);
- endItemIdCopy.remove(itemId);
- // TODO: deal with targetIDs for itemIDs for ListView items
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
- }
- int startItemIdCopySize = startValues.itemIdValues.size();
- for (int i = 0; i < startItemIdCopySize; ++i) {
- long id = startValues.itemIdValues.keyAt(i);
- if (isValidTarget(null, id)) {
- TransitionValues start = startValues.itemIdValues.get(id);
- TransitionValues end = endValues.itemIdValues.get(id);
- endItemIdCopy.remove(id);
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
- // Now walk through the remains of the end set
- // We've already matched everything from start to end, everything else doesn't match.
- for (View view : endCopy.keySet()) {
- int id = view.getId();
- if (isValidTarget(view, id)) {
- TransitionValues start = null;
- TransitionValues end = endCopy.get(view);
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
+ matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.nameValues, endValues.nameValues);
+ matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+ matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.idValues, endValues.idValues);
+ matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.itemIdValues, endValues.itemIdValues);
+ addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
long minStartDelay = Long.MAX_VALUE;
int minAnimator = mAnimators.size();
@@ -520,7 +597,8 @@ public abstract class Transition implements Cloneable {
* is not checked (this is in the case of ListView items, where the
* views are ignored and only the ids are used).
*/
- boolean isValidTarget(View target, long targetId) {
+ boolean isValidTarget(View target) {
+ int targetId = target.getId();
if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) {
return false;
}
@@ -536,10 +614,20 @@ public abstract class Transition implements Cloneable {
}
}
}
- if (mTargetIds.size() == 0 && mTargets.size() == 0 && mTargetTypes == null) {
+ if (mTargetNameExcludes != null && target != null && target.getViewName() != null) {
+ if (mTargetNameExcludes.contains(target.getViewName())) {
+ return false;
+ }
+ }
+ if (mTargetIds.size() == 0 && mTargets.size() == 0 &&
+ (mTargetTypes == null || mTargetTypes.isEmpty() &&
+ (mTargetNames == null || mTargetNames.isEmpty()))) {
+ return true;
+ }
+ if (mTargetIds.contains(targetId) || mTargets.contains(target)) {
return true;
}
- if (mTargetIds.contains((int) targetId) || mTargets.contains(target)) {
+ if (mTargetNames != null && mTargetNames.contains(target.getViewName())) {
return true;
}
if (mTargetTypes != null) {
@@ -690,6 +778,33 @@ public abstract class Transition implements Cloneable {
}
/**
+ * Adds the viewName of a target view that this Transition is interested in
+ * animating. By default, there are no targetNames, and a Transition will
+ * listen for changes on every view in the hierarchy below the sceneRoot
+ * of the Scene being transitioned into. Setting targetNames constrains
+ * the Transition to only listen for, and act on, views with these viewNames.
+ * Views with different viewNames, or no viewName whatsoever, will be ignored.
+ *
+ * <p>Note that viewNames should be unique within the view hierarchy.</p>
+ *
+ * @see android.view.View#getViewName()
+ * @param targetName The viewName of a target view, must be non-null.
+ * @return The Transition to which the target viewName is added.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).addTarget(someName);</code>
+ */
+ public Transition addTarget(String targetName) {
+ if (targetName != null) {
+ if (mTargetNames != null) {
+ mTargetNames = new ArrayList<String>();
+ }
+ mTargetNames.add(targetName);
+ }
+ return this;
+ }
+
+ /**
* Adds the Class of a target view that this Transition is interested in
* animating. By default, there are no targetTypes, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
@@ -712,10 +827,12 @@ public abstract class Transition implements Cloneable {
* <code>transitionSet.addTransitions(new Fade()).addTarget(ImageView.class);</code>
*/
public Transition addTarget(Class targetType) {
- if (mTargetTypes == null) {
- mTargetTypes = new ArrayList<Class>();
+ if (targetType != null) {
+ if (mTargetTypes == null) {
+ mTargetTypes = new ArrayList<Class>();
+ }
+ mTargetTypes.add(targetType);
}
- mTargetTypes.add(targetType);
return this;
}
@@ -737,6 +854,23 @@ public abstract class Transition implements Cloneable {
}
/**
+ * Removes the given targetName from the list of viewNames that this Transition
+ * is interested in animating.
+ *
+ * @param targetName The viewName of a target view, must not be null.
+ * @return The Transition from which the targetName is removed.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).removeTargetName(someName);</code>
+ */
+ public Transition removeTarget(String targetName) {
+ if (targetName != null && mTargetNames != null) {
+ mTargetNames.remove(targetName);
+ }
+ return this;
+ }
+
+ /**
* Whether to add the given id to the list of target ids to exclude from this
* transition. The <code>exclude</code> parameter specifies whether the target
* should be added to or removed from the excluded list.
@@ -758,7 +892,35 @@ public abstract class Transition implements Cloneable {
* @return This transition object.
*/
public Transition excludeTarget(int targetId, boolean exclude) {
- mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
+ if (targetId >= 0) {
+ mTargetIdExcludes = excludeObject(mTargetIdExcludes, targetId, exclude);
+ }
+ return this;
+ }
+
+ /**
+ * Whether to add the given viewName to the list of target viewNames to exclude from this
+ * transition. The <code>exclude</code> parameter specifies whether the target
+ * should be added to or removed from the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded by their
+ * id, their instance reference, their viewName, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeTarget(View, boolean)
+ * @see #excludeTarget(int, boolean)
+ * @see #excludeTarget(Class, boolean)
+ *
+ * @param targetViewName The name of a target to ignore when running this transition.
+ * @param exclude Whether to add the target to or remove the target from the
+ * current list of excluded targets.
+ * @return This transition object.
+ */
+ public Transition excludeTarget(String targetViewName, boolean exclude) {
+ mTargetNameExcludes = excludeObject(mTargetNameExcludes, targetViewName, exclude);
return this;
}
@@ -788,23 +950,10 @@ public abstract class Transition implements Cloneable {
* @return This transition object.
*/
public Transition excludeChildren(int targetId, boolean exclude) {
- mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
- return this;
- }
-
- /**
- * Utility method to manage the boilerplate code that is the same whether we
- * are excluding targets or their children.
- */
- private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
- if (targetId > 0) {
- if (exclude) {
- list = ArrayListManager.add(list, targetId);
- } else {
- list = ArrayListManager.remove(list, targetId);
- }
+ if (targetId >= 0) {
+ mTargetIdChildExcludes = excludeObject(mTargetIdChildExcludes, targetId, exclude);
}
- return list;
+ return this;
}
/**
@@ -829,7 +978,7 @@ public abstract class Transition implements Cloneable {
* @return This transition object.
*/
public Transition excludeTarget(View target, boolean exclude) {
- mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
+ mTargetExcludes = excludeObject(mTargetExcludes, target, exclude);
return this;
}
@@ -855,7 +1004,7 @@ public abstract class Transition implements Cloneable {
* @return This transition object.
*/
public Transition excludeChildren(View target, boolean exclude) {
- mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
+ mTargetChildExcludes = excludeObject(mTargetChildExcludes, target, exclude);
return this;
}
@@ -863,7 +1012,7 @@ public abstract class Transition implements Cloneable {
* Utility method to manage the boilerplate code that is the same whether we
* are excluding targets or their children.
*/
- private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
+ private static <T> ArrayList<T> excludeObject(ArrayList<T> list, T target, boolean exclude) {
if (target != null) {
if (exclude) {
list = ArrayListManager.add(list, target);
@@ -896,7 +1045,7 @@ public abstract class Transition implements Cloneable {
* @return This transition object.
*/
public Transition excludeTarget(Class type, boolean exclude) {
- mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
+ mTargetTypeExcludes = excludeObject(mTargetTypeExcludes, type, exclude);
return this;
}
@@ -923,26 +1072,11 @@ public abstract class Transition implements Cloneable {
* @return This transition object.
*/
public Transition excludeChildren(Class type, boolean exclude) {
- mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
+ mTargetTypeChildExcludes = excludeObject(mTargetTypeChildExcludes, type, exclude);
return this;
}
/**
- * Utility method to manage the boilerplate code that is the same whether we
- * are excluding targets or their children.
- */
- private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
- if (type != null) {
- if (exclude) {
- list = ArrayListManager.add(list, type);
- } else {
- list = ArrayListManager.remove(list, type);
- }
- }
- return list;
- }
-
- /**
* Sets the target view instances that this Transition is interested in
* animating. By default, there are no targets, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
@@ -991,9 +1125,27 @@ public abstract class Transition implements Cloneable {
}
/**
- * Returns the array of target IDs that this transition limits itself to
- * tracking and animating. If the array is null for both this method and
- * {@link #getTargets()}, then this transition is
+ * Removes the given target from the list of targets that this Transition
+ * is interested in animating.
+ *
+ * @param target The type of the target view, must be non-null.
+ * @return Transition The Transition from which the target is removed.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).removeTarget(someType);</code>
+ */
+ public Transition removeTarget(Class target) {
+ if (target != null) {
+ mTargetTypes.remove(target);
+ }
+ return this;
+ }
+
+ /**
+ * Returns the list of target IDs that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
* not limited to specific views, and will handle changes to any views
* in the hierarchy of a scene change.
*
@@ -1004,9 +1156,10 @@ public abstract class Transition implements Cloneable {
}
/**
- * Returns the array of target views that this transition limits itself to
- * tracking and animating. If the array is null for both this method and
- * {@link #getTargetIds()}, then this transition is
+ * Returns the list of target views that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
* not limited to specific views, and will handle changes to any views
* in the hierarchy of a scene change.
*
@@ -1017,6 +1170,34 @@ public abstract class Transition implements Cloneable {
}
/**
+ * Returns the list of target viewNames that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
+ * not limited to specific views, and will handle changes to any views
+ * in the hierarchy of a scene change.
+ *
+ * @return the list of target viewNames
+ */
+ public List<String> getTargetViewNames() {
+ return mTargetNames;
+ }
+
+ /**
+ * Returns the list of target viewNames that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
+ * not limited to specific views, and will handle changes to any views
+ * in the hierarchy of a scene change.
+ *
+ * @return the list of target Types
+ */
+ public List<Class> getTargetTypes() {
+ return mTargetTypes;
+ }
+
+ /**
* Recursive method that captures values for the given view and the
* hierarchy underneath it.
* @param sceneRoot The root of the view hierarchy being captured
@@ -1025,52 +1206,42 @@ public abstract class Transition implements Cloneable {
*/
void captureValues(ViewGroup sceneRoot, boolean start) {
clearValues(start);
- if (mTargetIds.size() > 0 || mTargets.size() > 0) {
- if (mTargetIds.size() > 0) {
- for (int i = 0; i < mTargetIds.size(); ++i) {
- int id = mTargetIds.get(i);
- View view = sceneRoot.findViewById(id);
- if (view != null) {
- TransitionValues values = new TransitionValues();
- values.view = view;
- if (start) {
- captureStartValues(values);
- } else {
- captureEndValues(values);
- }
- capturePropagationValues(values);
- if (start) {
- mStartValues.viewValues.put(view, values);
- if (id >= 0) {
- mStartValues.idValues.put(id, values);
- }
- } else {
- mEndValues.viewValues.put(view, values);
- if (id >= 0) {
- mEndValues.idValues.put(id, values);
- }
- }
+ if ((mTargetIds.size() > 0 || mTargets.size() > 0)
+ && (mTargetNames == null || mTargetNames.isEmpty())
+ && (mTargetTypes == null || mTargetTypes.isEmpty())) {
+ for (int i = 0; i < mTargetIds.size(); ++i) {
+ int id = mTargetIds.get(i);
+ View view = sceneRoot.findViewById(id);
+ if (view != null) {
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ if (start) {
+ captureStartValues(values);
+ } else {
+ captureEndValues(values);
+ }
+ capturePropagationValues(values);
+ if (start) {
+ addViewValues(mStartValues, view, values);
+ } else {
+ addViewValues(mEndValues, view, values);
}
}
}
- if (mTargets.size() > 0) {
- for (int i = 0; i < mTargets.size(); ++i) {
- View view = mTargets.get(i);
- if (view != null) {
- TransitionValues values = new TransitionValues();
- values.view = view;
- if (start) {
- captureStartValues(values);
- } else {
- captureEndValues(values);
- }
- capturePropagationValues(values);
- if (start) {
- mStartValues.viewValues.put(view, values);
- } else {
- mEndValues.viewValues.put(view, values);
- }
- }
+ for (int i = 0; i < mTargets.size(); ++i) {
+ View view = mTargets.get(i);
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ if (start) {
+ captureStartValues(values);
+ } else {
+ captureEndValues(values);
+ }
+ capturePropagationValues(values);
+ if (start) {
+ mStartValues.viewValues.put(view, values);
+ } else {
+ mEndValues.viewValues.put(view, values);
}
}
} else {
@@ -1078,6 +1249,47 @@ public abstract class Transition implements Cloneable {
}
}
+ static void addViewValues(TransitionValuesMaps transitionValuesMaps,
+ View view, TransitionValues transitionValues) {
+ transitionValuesMaps.viewValues.put(view, transitionValues);
+ int id = view.getId();
+ if (id >= 0) {
+ if (transitionValuesMaps.idValues.indexOfKey(id) >= 0) {
+ // Duplicate IDs cannot match by ID.
+ transitionValuesMaps.idValues.put(id, null);
+ } else {
+ transitionValuesMaps.idValues.put(id, view);
+ }
+ }
+ String name = view.getViewName();
+ if (name != null) {
+ if (transitionValuesMaps.nameValues.containsKey(name)) {
+ // Duplicate viewNames: cannot match by viewName.
+ transitionValuesMaps.nameValues.put(name, null);
+ } else {
+ transitionValuesMaps.nameValues.put(name, view);
+ }
+ }
+ if (view.getParent() instanceof ListView) {
+ ListView listview = (ListView) view.getParent();
+ if (listview.getAdapter().hasStableIds()) {
+ int position = listview.getPositionForView(view);
+ long itemId = listview.getItemIdAtPosition(position);
+ if (transitionValuesMaps.itemIdValues.indexOfKey(itemId) >= 0) {
+ // Duplicate item IDs: cannot match by item ID.
+ View alreadyMatched = transitionValuesMaps.itemIdValues.get(itemId);
+ if (alreadyMatched != null) {
+ alreadyMatched.setHasTransientState(false);
+ transitionValuesMaps.itemIdValues.put(itemId, null);
+ }
+ } else {
+ view.setHasTransientState(true);
+ transitionValuesMaps.itemIdValues.put(itemId, view);
+ }
+ }
+ }
+ }
+
/**
* Clear valuesMaps for specified start/end state
*
@@ -1109,24 +1321,7 @@ public abstract class Transition implements Cloneable {
if (view == null) {
return;
}
- boolean isListViewItem = false;
- if (view.getParent() instanceof ListView) {
- isListViewItem = true;
- }
- if (isListViewItem && !((ListView) view.getParent()).getAdapter().hasStableIds()) {
- // ignore listview children unless we can track them with stable IDs
- return;
- }
- int id = View.NO_ID;
- long itemId = View.NO_ID;
- if (!isListViewItem) {
- id = view.getId();
- } else {
- ListView listview = (ListView) view.getParent();
- int position = listview.getPositionForView(view);
- itemId = listview.getItemIdAtPosition(position);
- view.setHasTransientState(true);
- }
+ int id = view.getId();
if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
return;
}
@@ -1151,23 +1346,9 @@ public abstract class Transition implements Cloneable {
}
capturePropagationValues(values);
if (start) {
- if (!isListViewItem) {
- mStartValues.viewValues.put(view, values);
- if (id >= 0) {
- mStartValues.idValues.put((int) id, values);
- }
- } else {
- mStartValues.itemIdValues.put(itemId, values);
- }
+ addViewValues(mStartValues, view, values);
} else {
- if (!isListViewItem) {
- mEndValues.viewValues.put(view, values);
- if (id >= 0) {
- mEndValues.idValues.put((int) id, values);
- }
- } else {
- mEndValues.itemIdValues.put(itemId, values);
- }
+ addViewValues(mEndValues, view, values);
}
}
if (view instanceof ViewGroup) {
@@ -1178,7 +1359,7 @@ public abstract class Transition implements Cloneable {
if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
return;
}
- if (mTargetTypeChildExcludes != null && view != null) {
+ if (mTargetTypeChildExcludes != null) {
int numTypes = mTargetTypeChildExcludes.size();
for (int i = 0; i < numTypes; ++i) {
if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
@@ -1204,22 +1385,7 @@ public abstract class Transition implements Cloneable {
return mParent.getTransitionValues(view, start);
}
TransitionValuesMaps valuesMaps = start ? mStartValues : mEndValues;
- TransitionValues values = valuesMaps.viewValues.get(view);
- if (values == null) {
- int id = view.getId();
- if (id >= 0) {
- values = valuesMaps.idValues.get(id);
- }
- if (values == null && view.getParent() instanceof ListView) {
- ListView listview = (ListView) view.getParent();
- int position = listview.getPositionForView(view);
- long itemId = listview.getItemIdAtPosition(position);
- values = valuesMaps.itemIdValues.get(itemId);
- }
- // TODO: Doesn't handle the case where a view was parented to a
- // ListView (with an itemId), but no longer is
- }
- return values;
+ return valuesMaps.viewValues.get(view);
}
/**
@@ -1303,11 +1469,7 @@ public abstract class Transition implements Cloneable {
boolean cancel = false;
TransitionValues oldValues = oldInfo.values;
View oldView = oldInfo.view;
- TransitionValues newValues = mEndValues.viewValues != null ?
- mEndValues.viewValues.get(oldView) : null;
- if (newValues == null) {
- newValues = mEndValues.idValues.get(oldView.getId());
- }
+ TransitionValues newValues = mEndValues.viewValues.get(oldView);
if (oldValues != null) {
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
@@ -1429,17 +1591,15 @@ public abstract class Transition implements Cloneable {
}
}
for (int i = 0; i < mStartValues.itemIdValues.size(); ++i) {
- TransitionValues tv = mStartValues.itemIdValues.valueAt(i);
- View v = tv.view;
- if (v.hasTransientState()) {
- v.setHasTransientState(false);
+ View view = mStartValues.itemIdValues.valueAt(i);
+ if (view != null) {
+ view.setHasTransientState(false);
}
}
for (int i = 0; i < mEndValues.itemIdValues.size(); ++i) {
- TransitionValues tv = mEndValues.itemIdValues.valueAt(i);
- View v = tv.view;
- if (v.hasTransientState()) {
- v.setHasTransientState(false);
+ View view = mEndValues.itemIdValues.valueAt(i);
+ if (view != null) {
+ view.setHasTransientState(false);
}
}
mEnded = true;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index a5e960a..04f8672 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -229,11 +229,20 @@ public class TransitionInflater {
com.android.internal.R.styleable.TransitionTarget);
int id = a.getResourceId(
com.android.internal.R.styleable.TransitionTarget_targetId, -1);
+ String viewName;
if (id >= 0) {
transition.addTarget(id);
} else if ((id = a.getResourceId(
com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) {
transition.excludeTarget(id, true);
+ } else if ((viewName = a.getString(
+ com.android.internal.R.styleable.TransitionTarget_targetViewName))
+ != null) {
+ transition.addTarget(viewName);
+ } else if ((viewName = a.getString(
+ com.android.internal.R.styleable.TransitionTarget_excludeViewName))
+ != null) {
+ transition.excludeTarget(viewName, true);
} else {
String className = a.getString(
com.android.internal.R.styleable.TransitionTarget_excludeClass);
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 9081234..698b563 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -272,24 +272,8 @@ public class TransitionSet extends Transition {
int numValues = values.viewValues.size();
for (int i = 0; i < numValues; i++) {
View view = values.viewValues.keyAt(i);
- if (isValidTarget(view, view.getId())) {
- included.viewValues.put(view, values.viewValues.valueAt(i));
- }
- }
- numValues = values.idValues.size();
- for (int i = 0; i < numValues; i++) {
- int id = values.idValues.keyAt(i);
- TransitionValues transitionValues = values.idValues.valueAt(i);
- if (isValidTarget(transitionValues.view, id)) {
- included.idValues.put(id, transitionValues);
- }
- }
- numValues = values.itemIdValues.size();
- for (int i = 0; i < numValues; i++) {
- long id = values.itemIdValues.keyAt(i);
- TransitionValues transitionValues = values.itemIdValues.valueAt(i);
- if (isValidTarget(transitionValues.view, id)) {
- included.itemIdValues.put(id, transitionValues);
+ if (isValidTarget(view)) {
+ addViewValues(included, view, values.viewValues.valueAt(i));
}
}
return included;
@@ -328,10 +312,9 @@ public class TransitionSet extends Transition {
@Override
public void captureStartValues(TransitionValues transitionValues) {
- int targetId = transitionValues.view.getId();
- if (isValidTarget(transitionValues.view, targetId)) {
+ if (isValidTarget(transitionValues.view)) {
for (Transition childTransition : mTransitions) {
- if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ if (childTransition.isValidTarget(transitionValues.view)) {
childTransition.captureStartValues(transitionValues);
}
}
@@ -340,10 +323,9 @@ public class TransitionSet extends Transition {
@Override
public void captureEndValues(TransitionValues transitionValues) {
- int targetId = transitionValues.view.getId();
- if (isValidTarget(transitionValues.view, targetId)) {
+ if (isValidTarget(transitionValues.view)) {
for (Transition childTransition : mTransitions) {
- if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ if (childTransition.isValidTarget(transitionValues.view)) {
childTransition.captureEndValues(transitionValues);
}
}
diff --git a/core/java/android/transition/TransitionValuesMaps.java b/core/java/android/transition/TransitionValuesMaps.java
index 131596b..6d5700a 100644
--- a/core/java/android/transition/TransitionValuesMaps.java
+++ b/core/java/android/transition/TransitionValuesMaps.java
@@ -24,7 +24,7 @@ import android.view.View;
class TransitionValuesMaps {
ArrayMap<View, TransitionValues> viewValues =
new ArrayMap<View, TransitionValues>();
- SparseArray<TransitionValues> idValues = new SparseArray<TransitionValues>();
- LongSparseArray<TransitionValues> itemIdValues =
- new LongSparseArray<TransitionValues>();
+ SparseArray<View> idValues = new SparseArray<View>();
+ LongSparseArray<View> itemIdValues = new LongSparseArray<View>();
+ ArrayMap<String, View> nameValues = new ArrayMap<String, View>();
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 6e6496c..0f7638b 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -162,26 +162,15 @@ public abstract class Visibility extends Transition {
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
- if (visInfo.visibilityChange) {
- // Only transition views that are either targets of this transition
- // or whose parent hierarchies remain stable between scenes
- boolean isTarget = false;
- if (mTargets.size() > 0 || mTargetIds.size() > 0) {
- View startView = startValues != null ? startValues.view : null;
- View endView = endValues != null ? endValues.view : null;
- int startId = startView != null ? startView.getId() : -1;
- int endId = endView != null ? endView.getId() : -1;
- isTarget = isValidTarget(startView, startId) || isValidTarget(endView, endId);
- }
- if (isTarget || ((visInfo.startParent != null || visInfo.endParent != null))) {
- if (visInfo.fadeIn) {
- return onAppear(sceneRoot, startValues, visInfo.startVisibility,
- endValues, visInfo.endVisibility);
- } else {
- return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
- endValues, visInfo.endVisibility
- );
- }
+ if (visInfo.visibilityChange
+ && (visInfo.startParent != null || visInfo.endParent != null)) {
+ if (visInfo.fadeIn) {
+ return onAppear(sceneRoot, startValues, visInfo.startVisibility,
+ endValues, visInfo.endVisibility);
+ } else {
+ return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
+ endValues, visInfo.endVisibility
+ );
}
}
return null;
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 5653066..17035b1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -19,7 +19,11 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.Trace;
+import android.util.Log;
import android.util.TimeUtils;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
@@ -65,6 +69,8 @@ public class ThreadedRenderer extends HardwareRenderer {
private Choreographer mChoreographer;
ThreadedRenderer(boolean translucent) {
+ AtlasInitializer.sInstance.init();
+
long rootNodePtr = nCreateRootRenderNode();
mRootNode = RenderNode.adopt(rootNodePtr);
mRootNode.setClipToBounds(false);
@@ -292,8 +298,43 @@ public class ThreadedRenderer extends HardwareRenderer {
}
}
- /** @hide */
- public static native void postToRenderThread(Runnable runnable);
+ private static class AtlasInitializer {
+ static AtlasInitializer sInstance = new AtlasInitializer();
+
+ private boolean mInitialized = false;
+
+ private AtlasInitializer() {}
+
+ synchronized void init() {
+ if (mInitialized) return;
+ IBinder binder = ServiceManager.getService("assetatlas");
+ if (binder == null) return;
+
+ IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+ try {
+ if (atlas.isCompatible(android.os.Process.myPpid())) {
+ GraphicBuffer buffer = atlas.getBuffer();
+ if (buffer != null) {
+ long[] map = atlas.getMap();
+ if (map != null) {
+ nSetAtlas(buffer, map);
+ mInitialized = true;
+ }
+ // If IAssetAtlas is not the same class as the IBinder
+ // we are using a remote service and we can safely
+ // destroy the graphic buffer
+ if (atlas.getClass() != binder.getClass()) {
+ buffer.destroy();
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Could not acquire atlas", e);
+ }
+ }
+ }
+
+ private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
private static native long nCreateRootRenderNode();
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bef96b1..e829141 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -670,7 +670,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
* @attr ref android.R.styleable#View_stateListAnimator
- * @attr ref android.R.styleable#View_sharedElementName
+ * @attr ref android.R.styleable#View_viewName
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
* @attr ref android.R.styleable#View_textAlignment
@@ -3185,6 +3185,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private int mBackgroundResource;
private boolean mBackgroundSizeChanged;
+ private String mViewName;
+
static class ListenerInfo {
/**
* Listener used to dispatch focus change events.
@@ -3997,8 +3999,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case R.styleable.View_accessibilityLiveRegion:
setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
break;
- case R.styleable.View_sharedElementName:
- setSharedElementName(a.getString(attr));
+ case R.styleable.View_viewName:
+ setViewName(a.getString(attr));
break;
case R.styleable.View_nestedScrollingEnabled:
setNestedScrollingEnabled(a.getBoolean(attr, false));
@@ -18839,15 +18841,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Adds all Views that have {@link #getSharedElementName()} non-null to sharedElements.
- * @param sharedElements Will contain all Views in the hierarchy having a shared element name.
+ * Adds all Views that have {@link #getViewName()} non-null to namedElements.
+ * @param namedElements Will contain all Views in the hierarchy having a view name.
* @hide
*/
- public void findSharedElements(Map<String, View> sharedElements) {
+ public void findNamedViews(Map<String, View> namedElements) {
if (getVisibility() == VISIBLE) {
- String sharedElementName = getSharedElementName();
- if (sharedElementName != null) {
- sharedElements.put(sharedElementName, this);
+ String viewName = getViewName();
+ if (viewName != null) {
+ namedElements.put(viewName, this);
}
}
}
@@ -19247,32 +19249,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Specifies that the shared name of the View to be shared with another Activity.
- * When transitioning between Activities, the name links a UI element in the starting
- * Activity to UI element in the called Activity. Names should be unique in the
- * View hierarchy.
+ * Sets the name of the View to be used to identify Views in Transitions.
+ * Names should be unique in the View hierarchy.
*
- * @param sharedElementName The cross-Activity View identifier. The called Activity will use
- * the name to match the location with a View in its layout.
- * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+ * @param viewName The name of the View to uniquely identify it for Transitions.
*/
- public void setSharedElementName(String sharedElementName) {
- setTagInternal(com.android.internal.R.id.shared_element_name, sharedElementName);
+ public final void setViewName(String viewName) {
+ mViewName = viewName;
}
/**
- * Returns the shared name of the View to be shared with another Activity.
- * When transitioning between Activities, the name links a UI element in the starting
- * Activity to UI element in the called Activity. Names should be unique in the
- * View hierarchy.
+ * Returns the name of the View to be used to identify Views in Transitions.
+ * Names should be unique in the View hierarchy.
*
- * <p>This returns null if the View is not a shared element or the name if it is.</p>
+ * <p>This returns null if the View has not been given a name.</p>
*
- * @return The name used for this View for cross-Activity transitions or null if
- * this View has not been identified as shared.
+ * @return The name used of the View to be used to identify Views in Transitions or null
+ * if no name has been given.
*/
- public String getSharedElementName() {
- return (String) getTag(com.android.internal.R.id.shared_element_name);
+ public String getViewName() {
+ return mViewName;
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4309366..92a42b7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2301,13 +2301,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* individually during the transition.
* @return True if the ViewGroup should be acted on together during an Activity transition.
* The default value is false when the background is null and true when the background
- * is not null or if {@link #getSharedElementName()} is not null.
+ * is not null or if {@link #getViewName()} is not null.
*/
public boolean isTransitionGroup() {
if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
} else {
- return getBackground() != null || getSharedElementName() != null;
+ return getBackground() != null || getViewName() != null;
}
}
@@ -5956,15 +5956,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/** @hide */
@Override
- public void findSharedElements(Map<String, View> sharedElements) {
+ public void findNamedViews(Map<String, View> namedElements) {
if (getVisibility() != VISIBLE) {
return;
}
- super.findSharedElements(sharedElements);
+ super.findNamedViews(namedElements);
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- child.findSharedElements(sharedElements);
+ child.findNamedViews(namedElements);
}
}