Merge "Setting ADB_ENABLED may result in a SecurityException." into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index c9d7579..fb26daf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28691,7 +28691,7 @@
method public java.lang.String getSubscriberId();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
- method public int hasCarrierPrivileges();
+ method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
@@ -28711,10 +28711,6 @@
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
- field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
- field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
- field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
- field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4
field public static final int DATA_ACTIVITY_IN = 1; // 0x1
field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 948c9a2..bd34a9c 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -501,7 +501,7 @@
@Override
public void onExecute(IContentProvider provider) throws Exception {
- final ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null);
+ final ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null);
copy(new FileInputStream(fd.getFileDescriptor()), System.out);
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c3028b7..6ec48e5 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1186,6 +1186,18 @@
return true;
}
+ case CHECK_PERMISSION_WITH_TOKEN_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String perm = data.readString();
+ int pid = data.readInt();
+ int uid = data.readInt();
+ IBinder token = data.readStrongBinder();
+ int res = checkPermissionWithToken(perm, pid, uid, token);
+ reply.writeNoException();
+ reply.writeInt(res);
+ return true;
+ }
+
case CHECK_URI_PERMISSION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
Uri uri = Uri.CREATOR.createFromParcel(data);
@@ -1193,7 +1205,8 @@
int uid = data.readInt();
int mode = data.readInt();
int userId = data.readInt();
- int res = checkUriPermission(uri, pid, uid, mode, userId);
+ IBinder callerToken = data.readStrongBinder();
+ int res = checkUriPermission(uri, pid, uid, mode, userId, callerToken);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -3742,7 +3755,7 @@
mRemote.transact(GET_INTENT_SENDER_TRANSACTION, data, reply, 0);
reply.readException();
IIntentSender res = IIntentSender.Stub.asInterface(
- reply.readStrongBinder());
+ reply.readStrongBinder());
data.recycle();
reply.recycle();
return res;
@@ -3851,6 +3864,22 @@
reply.recycle();
return res;
}
+ public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(permission);
+ data.writeInt(pid);
+ data.writeInt(uid);
+ data.writeStrongBinder(callerToken);
+ mRemote.transact(CHECK_PERMISSION_WITH_TOKEN_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, final int userId) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -3866,8 +3895,8 @@
reply.recycle();
return res;
}
- public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
- throws RemoteException {
+ public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId,
+ IBinder callerToken) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3876,6 +3905,7 @@
data.writeInt(uid);
data.writeInt(mode);
data.writeInt(userId);
+ data.writeStrongBinder(callerToken);
mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7fafc38..1de9b47 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1863,6 +1863,21 @@
}
}
+ /** @hide */
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ if (permission == null) {
+ throw new IllegalArgumentException("permission is null");
+ }
+
+ try {
+ return ActivityManagerNative.getDefault().checkPermissionWithToken(
+ permission, pid, uid, callerToken);
+ } catch (RemoteException e) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
@Override
public int checkCallingPermission(String permission) {
if (permission == null) {
@@ -1951,7 +1966,19 @@
try {
return ActivityManagerNative.getDefault().checkUriPermission(
ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
- resolveUserId(uri));
+ resolveUserId(uri), null);
+ } catch (RemoteException e) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+
+ /** @hide */
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+ try {
+ return ActivityManagerNative.getDefault().checkUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
+ resolveUserId(uri), callerToken);
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6433f3f..5362303 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -219,9 +219,11 @@
public int checkPermission(String permission, int pid, int uid)
throws RemoteException;
-
- public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
+ public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken)
throws RemoteException;
+
+ public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId,
+ IBinder callerToken) 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)
@@ -785,4 +787,5 @@
int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238;
int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239;
int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
+ int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 4c82efd..360f308 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -31,6 +31,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
@@ -201,7 +202,7 @@
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
@@ -227,7 +228,7 @@
validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
final String original = setCallingPackage(callingPkg);
@@ -242,7 +243,7 @@
public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
final String original = setCallingPackage(callingPkg);
@@ -270,13 +271,13 @@
operations.set(i, operation);
}
if (operation.isReadOperation()) {
- if (enforceReadPermission(callingPkg, uri)
+ if (enforceReadPermission(callingPkg, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
if (operation.isWriteOperation()) {
- if (enforceWritePermission(callingPkg, uri)
+ if (enforceWritePermission(callingPkg, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
@@ -301,7 +302,7 @@
public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
final String original = setCallingPackage(callingPkg);
@@ -317,7 +318,7 @@
String[] selectionArgs) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
final String original = setCallingPackage(callingPkg);
@@ -330,11 +331,11 @@
@Override
public ParcelFileDescriptor openFile(
- String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
- throws FileNotFoundException {
+ String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
+ IBinder callerToken) throws FileNotFoundException {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- enforceFilePermission(callingPkg, uri, mode);
+ enforceFilePermission(callingPkg, uri, mode, callerToken);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openFile(
@@ -350,7 +351,7 @@
throws FileNotFoundException {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- enforceFilePermission(callingPkg, uri, mode);
+ enforceFilePermission(callingPkg, uri, mode, null);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openAssetFile(
@@ -382,7 +383,7 @@
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- enforceFilePermission(callingPkg, uri, "r");
+ enforceFilePermission(callingPkg, uri, "r", null);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openTypedAssetFile(
@@ -402,7 +403,7 @@
validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return null;
}
final String original = setCallingPackage(callingPkg);
@@ -418,7 +419,7 @@
validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return null;
}
final String original = setCallingPackage(callingPkg);
@@ -429,29 +430,33 @@
}
}
- private void enforceFilePermission(String callingPkg, Uri uri, String mode)
- throws FileNotFoundException, SecurityException {
+ private void enforceFilePermission(String callingPkg, Uri uri, String mode,
+ IBinder callerToken) throws FileNotFoundException, SecurityException {
if (mode != null && mode.indexOf('w') != -1) {
- if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceWritePermission(callingPkg, uri, callerToken)
+ != AppOpsManager.MODE_ALLOWED) {
throw new FileNotFoundException("App op not allowed");
}
} else {
- if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ if (enforceReadPermission(callingPkg, uri, callerToken)
+ != AppOpsManager.MODE_ALLOWED) {
throw new FileNotFoundException("App op not allowed");
}
}
}
- private int enforceReadPermission(String callingPkg, Uri uri) throws SecurityException {
- enforceReadPermissionInner(uri);
+ private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
+ throws SecurityException {
+ enforceReadPermissionInner(uri, callerToken);
if (mReadOp != AppOpsManager.OP_NONE) {
return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg);
}
return AppOpsManager.MODE_ALLOWED;
}
- private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException {
- enforceWritePermissionInner(uri);
+ private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
+ throws SecurityException {
+ enforceWritePermissionInner(uri, callerToken);
if (mWriteOp != AppOpsManager.OP_NONE) {
return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg);
}
@@ -467,7 +472,8 @@
}
/** {@hide} */
- protected void enforceReadPermissionInner(Uri uri) throws SecurityException {
+ protected void enforceReadPermissionInner(Uri uri, IBinder callerToken)
+ throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -480,7 +486,8 @@
if (mExported && checkUser(pid, uid, context)) {
final String componentPerm = getReadPermission();
if (componentPerm != null) {
- if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
+ if (context.checkPermission(componentPerm, pid, uid, callerToken)
+ == PERMISSION_GRANTED) {
return;
} else {
missingPerm = componentPerm;
@@ -497,7 +504,8 @@
for (PathPermission pp : pps) {
final String pathPerm = pp.getReadPermission();
if (pathPerm != null && pp.match(path)) {
- if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+ if (context.checkPermission(pathPerm, pid, uid, callerToken)
+ == PERMISSION_GRANTED) {
return;
} else {
// any denied <path-permission> means we lose
@@ -518,8 +526,8 @@
final int callingUserId = UserHandle.getUserId(uid);
final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid))
? maybeAddUserId(uri, callingUserId) : uri;
- if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- == PERMISSION_GRANTED) {
+ if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ callerToken) == PERMISSION_GRANTED) {
return;
}
@@ -532,7 +540,8 @@
}
/** {@hide} */
- protected void enforceWritePermissionInner(Uri uri) throws SecurityException {
+ protected void enforceWritePermissionInner(Uri uri, IBinder callerToken)
+ throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -545,7 +554,8 @@
if (mExported && checkUser(pid, uid, context)) {
final String componentPerm = getWritePermission();
if (componentPerm != null) {
- if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
+ if (context.checkPermission(componentPerm, pid, uid, callerToken)
+ == PERMISSION_GRANTED) {
return;
} else {
missingPerm = componentPerm;
@@ -562,7 +572,8 @@
for (PathPermission pp : pps) {
final String pathPerm = pp.getWritePermission();
if (pathPerm != null && pp.match(path)) {
- if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+ if (context.checkPermission(pathPerm, pid, uid, callerToken)
+ == PERMISSION_GRANTED) {
return;
} else {
// any denied <path-permission> means we lose
@@ -580,8 +591,8 @@
}
// last chance, check against any uri grants
- if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
- == PERMISSION_GRANTED) {
+ if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ callerToken) == PERMISSION_GRANTED) {
return;
}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index cefc27f..e15ac94 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -288,7 +288,7 @@
remoteSignal = mContentProvider.createCancellationSignal();
signal.setRemote(remoteSignal);
}
- return mContentProvider.openFile(mPackageName, url, mode, remoteSignal);
+ return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 39286d6..f2e7fc4 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -234,9 +234,10 @@
String mode = data.readString();
ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
+ IBinder callerToken = data.readStrongBinder();
ParcelFileDescriptor fd;
- fd = openFile(callingPkg, url, mode, signal);
+ fd = openFile(callingPkg, url, mode, signal, callerToken);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
@@ -575,7 +576,7 @@
@Override
public ParcelFileDescriptor openFile(
- String callingPkg, Uri url, String mode, ICancellationSignal signal)
+ String callingPkg, Uri url, String mode, ICancellationSignal signal, IBinder token)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -586,6 +587,7 @@
url.writeToParcel(data, 0);
data.writeString(mode);
data.writeStrongBinder(signal != null ? signal.asBinder() : null);
+ data.writeStrongBinder(token);
mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c9b7d0a..a73ba74 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -37,6 +37,7 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.StatFs;
import android.os.UserHandle;
@@ -2864,10 +2865,10 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.app.UsageStatsManager} for interacting with the status bar.
+ * android.app.usage.UsageStatsManager} for interacting with the status bar.
*
* @see #getSystemService
- * @see android.app.UsageStatsManager
+ * @see android.app.usage.UsageStatsManager
* @hide
*/
public static final String USAGE_STATS_SERVICE = "usagestats";
@@ -2921,6 +2922,11 @@
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
+ /** @hide */
+ @PackageManager.PermissionResult
+ public abstract int checkPermission(@NonNull String permission, int pid, int uid,
+ IBinder callerToken);
+
/**
* Determine whether the calling process of an IPC you are handling has been
* granted a particular permission. This is basically the same as calling
@@ -3108,6 +3114,10 @@
public abstract int checkUriPermission(Uri uri, int pid, int uid,
@Intent.AccessUriMode int modeFlags);
+ /** @hide */
+ public abstract int checkUriPermission(Uri uri, int pid, int uid,
+ @Intent.AccessUriMode int modeFlags, IBinder callerToken);
+
/**
* Determine whether the calling process and user ID has been
* granted permission to access a specific URI. This is basically
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index ad7c350..cfae1cf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -29,6 +29,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.view.DisplayAdjustments;
@@ -566,6 +567,12 @@
return mBase.checkPermission(permission, pid, uid);
}
+ /** @hide */
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ return mBase.checkPermission(permission, pid, uid, callerToken);
+ }
+
@Override
public int checkCallingPermission(String permission) {
return mBase.checkCallingPermission(permission);
@@ -608,6 +615,12 @@
return mBase.checkUriPermission(uri, pid, uid, modeFlags);
}
+ /** @hide */
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+ return mBase.checkUriPermission(uri, pid, uid, modeFlags, callerToken);
+ }
+
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
return mBase.checkCallingUriPermission(uri, modeFlags);
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index f92a404..f858406 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -47,7 +47,8 @@
public int update(String callingPkg, Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException;
public ParcelFileDescriptor openFile(
- String callingPkg, Uri url, String mode, ICancellationSignal signal)
+ String callingPkg, Uri url, String mode, ICancellationSignal signal,
+ IBinder callerToken)
throws RemoteException, FileNotFoundException;
public AssetFileDescriptor openAssetFile(
String callingPkg, Uri url, String mode, ICancellationSignal signal)
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 5b926ad..961a3f4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -60,4 +60,6 @@
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
+
+ void verifyNfcPermission();
}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index dd9765d..d009295 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -254,7 +254,11 @@
isResumed = state.resumed;
}
if (isResumed) {
+ // requestNfcServiceCallback() verifies permission also
requestNfcServiceCallback();
+ } else {
+ // Crash API calls early in case NFC permission is missing
+ verifyNfcPermission();
}
}
@@ -268,7 +272,11 @@
isResumed = state.resumed;
}
if (isResumed) {
+ // requestNfcServiceCallback() verifies permission also
requestNfcServiceCallback();
+ } else {
+ // Crash API calls early in case NFC permission is missing
+ verifyNfcPermission();
}
}
@@ -281,7 +289,11 @@
isResumed = state.resumed;
}
if (isResumed) {
+ // requestNfcServiceCallback() verifies permission also
requestNfcServiceCallback();
+ } else {
+ // Crash API calls early in case NFC permission is missing
+ verifyNfcPermission();
}
}
@@ -295,7 +307,11 @@
isResumed = state.resumed;
}
if (isResumed) {
+ // requestNfcServiceCallback() verifies permission also
requestNfcServiceCallback();
+ } else {
+ // Crash API calls early in case NFC permission is missing
+ verifyNfcPermission();
}
}
@@ -308,7 +324,11 @@
isResumed = state.resumed;
}
if (isResumed) {
+ // requestNfcServiceCallback() verifies permission also
requestNfcServiceCallback();
+ } else {
+ // Crash API calls early in case NFC permission is missing
+ verifyNfcPermission();
}
}
@@ -324,6 +344,14 @@
}
}
+ void verifyNfcPermission() {
+ try {
+ NfcAdapter.sService.verifyNfcPermission();
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+
/** Callback from NFC service, usually on binder thread */
@Override
public BeamShareData createBeamShareData() {
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 270d786..4135e8b 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -637,7 +637,7 @@
final Bundle out = new Bundle();
try {
if (METHOD_CREATE_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri);
+ enforceWritePermissionInner(documentUri, null);
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -651,7 +651,7 @@
out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
} else if (METHOD_RENAME_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri);
+ enforceWritePermissionInner(documentUri, null);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
final String newDocumentId = renameDocument(documentId, displayName);
@@ -675,7 +675,7 @@
}
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri);
+ enforceWritePermissionInner(documentUri, null);
deleteDocument(documentId);
// Document no longer exists, clean up any grants
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 5579c13..2c8a499 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -274,7 +274,7 @@
}
private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
updateViewTreeDisplayList(view);
if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1d19c9b..b54d462 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -56,6 +56,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -14405,143 +14406,158 @@
public void buildDrawingCache(boolean autoScale) {
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
mDrawingCache == null : mUnscaledDrawingCache == null)) {
- mCachingFailed = false;
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "buildDrawingCache/SW Layer for " + getClass().getSimpleName());
+ }
+ try {
+ buildDrawingCacheImpl(autoScale);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+ }
- int width = mRight - mLeft;
- int height = mBottom - mTop;
+ /**
+ * private, internal implementation of buildDrawingCache, used to enable tracing
+ */
+ private void buildDrawingCacheImpl(boolean autoScale) {
+ mCachingFailed = false;
- final AttachInfo attachInfo = mAttachInfo;
- final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
+ int width = mRight - mLeft;
+ int height = mBottom - mTop;
- if (autoScale && scalingRequired) {
- width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
- height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
+ final AttachInfo attachInfo = mAttachInfo;
+ final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
+
+ if (autoScale && scalingRequired) {
+ width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
+ height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
+ }
+
+ final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
+ final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
+ final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
+
+ final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
+ final long drawingCacheSize =
+ ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
+ if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
+ if (width > 0 && height > 0) {
+ Log.w(VIEW_LOG_TAG, "View too large to fit into drawing cache, needs "
+ + projectedBitmapSize + " bytes, only "
+ + drawingCacheSize + " available");
+ }
+ destroyDrawingCache();
+ mCachingFailed = true;
+ return;
+ }
+
+ boolean clear = true;
+ Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
+
+ if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
+ Bitmap.Config quality;
+ if (!opaque) {
+ // Never pick ARGB_4444 because it looks awful
+ // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
+ switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
+ case DRAWING_CACHE_QUALITY_AUTO:
+ case DRAWING_CACHE_QUALITY_LOW:
+ case DRAWING_CACHE_QUALITY_HIGH:
+ default:
+ quality = Bitmap.Config.ARGB_8888;
+ break;
+ }
+ } else {
+ // Optimization for translucent windows
+ // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
+ quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
}
- final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
- final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
- final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
+ // Try to cleanup memory
+ if (bitmap != null) bitmap.recycle();
- final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
- final long drawingCacheSize =
- ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
- if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
- if (width > 0 && height > 0) {
- Log.w(VIEW_LOG_TAG, "View too large to fit into drawing cache, needs "
- + projectedBitmapSize + " bytes, only "
- + drawingCacheSize + " available");
+ try {
+ bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
+ width, height, quality);
+ bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
+ if (autoScale) {
+ mDrawingCache = bitmap;
+ } else {
+ mUnscaledDrawingCache = bitmap;
}
- destroyDrawingCache();
+ if (opaque && use32BitCache) bitmap.setHasAlpha(false);
+ } catch (OutOfMemoryError e) {
+ // If there is not enough memory to create the bitmap cache, just
+ // ignore the issue as bitmap caches are not required to draw the
+ // view hierarchy
+ if (autoScale) {
+ mDrawingCache = null;
+ } else {
+ mUnscaledDrawingCache = null;
+ }
mCachingFailed = true;
return;
}
- boolean clear = true;
- Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
+ clear = drawingCacheBackgroundColor != 0;
+ }
- if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
- Bitmap.Config quality;
- if (!opaque) {
- // Never pick ARGB_4444 because it looks awful
- // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
- switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
- case DRAWING_CACHE_QUALITY_AUTO:
- case DRAWING_CACHE_QUALITY_LOW:
- case DRAWING_CACHE_QUALITY_HIGH:
- default:
- quality = Bitmap.Config.ARGB_8888;
- break;
- }
- } else {
- // Optimization for translucent windows
- // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
- quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- }
-
- // Try to cleanup memory
- if (bitmap != null) bitmap.recycle();
-
- try {
- bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
- width, height, quality);
- bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
- if (autoScale) {
- mDrawingCache = bitmap;
- } else {
- mUnscaledDrawingCache = bitmap;
- }
- if (opaque && use32BitCache) bitmap.setHasAlpha(false);
- } catch (OutOfMemoryError e) {
- // If there is not enough memory to create the bitmap cache, just
- // ignore the issue as bitmap caches are not required to draw the
- // view hierarchy
- if (autoScale) {
- mDrawingCache = null;
- } else {
- mUnscaledDrawingCache = null;
- }
- mCachingFailed = true;
- return;
- }
-
- clear = drawingCacheBackgroundColor != 0;
+ Canvas canvas;
+ if (attachInfo != null) {
+ canvas = attachInfo.mCanvas;
+ if (canvas == null) {
+ canvas = new Canvas();
}
+ canvas.setBitmap(bitmap);
+ // Temporarily clobber the cached Canvas in case one of our children
+ // is also using a drawing cache. Without this, the children would
+ // steal the canvas by attaching their own bitmap to it and bad, bad
+ // thing would happen (invisible views, corrupted drawings, etc.)
+ attachInfo.mCanvas = null;
+ } else {
+ // This case should hopefully never or seldom happen
+ canvas = new Canvas(bitmap);
+ }
- Canvas canvas;
- if (attachInfo != null) {
- canvas = attachInfo.mCanvas;
- if (canvas == null) {
- canvas = new Canvas();
- }
- canvas.setBitmap(bitmap);
- // Temporarily clobber the cached Canvas in case one of our children
- // is also using a drawing cache. Without this, the children would
- // steal the canvas by attaching their own bitmap to it and bad, bad
- // thing would happen (invisible views, corrupted drawings, etc.)
- attachInfo.mCanvas = null;
- } else {
- // This case should hopefully never or seldom happen
- canvas = new Canvas(bitmap);
+ if (clear) {
+ bitmap.eraseColor(drawingCacheBackgroundColor);
+ }
+
+ computeScroll();
+ final int restoreCount = canvas.save();
+
+ if (autoScale && scalingRequired) {
+ final float scale = attachInfo.mApplicationScale;
+ canvas.scale(scale, scale);
+ }
+
+ canvas.translate(-mScrollX, -mScrollY);
+
+ mPrivateFlags |= PFLAG_DRAWN;
+ if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
+ mLayerType != LAYER_TYPE_NONE) {
+ mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;
+ }
+
+ // Fast path for layouts with no backgrounds
+ if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
+ mPrivateFlags &= ~PFLAG_DIRTY_MASK;
+ dispatchDraw(canvas);
+ if (mOverlay != null && !mOverlay.isEmpty()) {
+ mOverlay.getOverlayView().draw(canvas);
}
+ } else {
+ draw(canvas);
+ }
- if (clear) {
- bitmap.eraseColor(drawingCacheBackgroundColor);
- }
+ canvas.restoreToCount(restoreCount);
+ canvas.setBitmap(null);
- computeScroll();
- final int restoreCount = canvas.save();
-
- if (autoScale && scalingRequired) {
- final float scale = attachInfo.mApplicationScale;
- canvas.scale(scale, scale);
- }
-
- canvas.translate(-mScrollX, -mScrollY);
-
- mPrivateFlags |= PFLAG_DRAWN;
- if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
- mLayerType != LAYER_TYPE_NONE) {
- mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;
- }
-
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- dispatchDraw(canvas);
- if (mOverlay != null && !mOverlay.isEmpty()) {
- mOverlay.getOverlayView().draw(canvas);
- }
- } else {
- draw(canvas);
- }
-
- canvas.restoreToCount(restoreCount);
- canvas.setBitmap(null);
-
- if (attachInfo != null) {
- // Restore the cached Canvas for our siblings
- attachInfo.mCanvas = canvas;
- }
+ if (attachInfo != null) {
+ // Restore the cached Canvas for our siblings
+ attachInfo.mCanvas = canvas;
}
}
@@ -15470,10 +15486,10 @@
&& mAttachInfo.mHardwareRenderer != null) {
mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
- final RenderNode displayList = mBackgroundRenderNode;
- if (displayList != null && displayList.isValid()) {
- setBackgroundDisplayListProperties(displayList);
- ((HardwareCanvas) canvas).drawRenderNode(displayList);
+ final RenderNode renderNode = mBackgroundRenderNode;
+ if (renderNode != null && renderNode.isValid()) {
+ setBackgroundRenderNodeProperties(renderNode);
+ ((HardwareCanvas) canvas).drawRenderNode(renderNode);
return;
}
}
@@ -15489,14 +15505,9 @@
}
}
- /**
- * Set up background drawable display list properties.
- *
- * @param displayList Valid display list for the background drawable
- */
- private void setBackgroundDisplayListProperties(RenderNode displayList) {
- displayList.setTranslationX(mScrollX);
- displayList.setTranslationY(mScrollY);
+ private void setBackgroundRenderNodeProperties(RenderNode renderNode) {
+ renderNode.setTranslationX(mScrollX);
+ renderNode.setTranslationY(mScrollY);
}
/**
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 674d7b8..3fdcaf7 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -28,6 +28,7 @@
android:layout_height="@dimen/notification_large_icon_height"
/>
<LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index ef916ed1..935424a 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -28,6 +28,7 @@
android:layout_height="@dimen/notification_large_icon_height"
/>
<LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 3415814..d0c10b2 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -28,6 +28,7 @@
android:layout_height="@dimen/notification_large_icon_height"
/>
<LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 8a66c3f..ac448ee 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -28,6 +28,7 @@
android:layout_height="@dimen/notification_large_icon_height"
/>
<LinearLayout
+ android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cbdb256..6e635f31 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1942,4 +1942,8 @@
<string-array translatable="false" name="config_sms_convert_destination_number_support">
<item>false</item>
</string-array>
+
+ <!-- The maximum bitmap size that can be written to a MediaMetadata object. This value
+ is the max width/height allowed in dips.-->
+ <dimen name="config_mediaMetadataBitmapMaxSize">320dp</dimen>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6135466..cbc379b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -202,6 +202,7 @@
<java-symbol type="id" name="status_bar_latest_event_content" />
<java-symbol type="id" name="action_divider" />
<java-symbol type="id" name="overflow_divider" />
+ <java-symbol type="id" name="notification_main_column" />
<java-symbol type="id" name="sms_short_code_confirm_message" />
<java-symbol type="id" name="sms_short_code_detail_layout" />
<java-symbol type="id" name="sms_short_code_detail_message" />
@@ -1809,6 +1810,8 @@
<java-symbol type="color" name="notification_progress_background_color" />
<java-symbol type="id" name="media_actions" />
+ <java-symbol type="dimen" name="config_mediaMetadataBitmapMaxSize" />
+
<!-- From SystemUI -->
<java-symbol type="anim" name="push_down_in" />
<java-symbol type="anim" name="push_down_out" />
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index b95636b..9aa29ca 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -20,11 +20,18 @@
#include "Caches.h"
#include "DeferredDisplayList.h"
-#include "RenderState.h"
#include "Layer.h"
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
#include "RenderNode.h"
+#include "RenderState.h"
+#include "utils/TraceUtils.h"
+
+#define ATRACE_LAYER_WORK(label) \
+ ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
+ label, \
+ (renderNode.get() != NULL) ? renderNode->getName() : "", \
+ getWidth(), getHeight())
namespace android {
namespace uirenderer {
@@ -223,6 +230,8 @@
}
void Layer::defer(const OpenGLRenderer& rootRenderer) {
+ ATRACE_LAYER_WORK("Optimize");
+
updateLightPosFromRenderer(rootRenderer);
const float width = layer.getWidth();
const float height = layer.getHeight();
@@ -260,6 +269,9 @@
void Layer::flush() {
// renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
if (deferredList && renderer) {
+ ATRACE_LAYER_WORK("Issue");
+ renderer->startMark((renderNode.get() != NULL) ? renderNode->getName() : "Layer");
+
renderer->setViewport(layer.getWidth(), layer.getHeight());
renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
!isBlend());
@@ -270,10 +282,14 @@
dirtyRect.setEmpty();
renderNode = NULL;
+
+ renderer->endMark();
}
}
void Layer::render(const OpenGLRenderer& rootRenderer) {
+ ATRACE_LAYER_WORK("Direct-Issue");
+
updateLightPosFromRenderer(rootRenderer);
renderer->setViewport(layer.getWidth(), layer.getHeight());
renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 394c647..83f9c6a 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -27,6 +27,7 @@
#include "Matrix.h"
#include "Properties.h"
#include "Rect.h"
+#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
@@ -185,7 +186,7 @@
///////////////////////////////////////////////////////////////////////////////
Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) {
- ATRACE_CALL();
+ ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height);
LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
Caches& caches = Caches::getInstance();
@@ -310,7 +311,7 @@
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
- ATRACE_CALL();
+ ATRACE_FORMAT("Destroy %ux%u HW Layer", layer->getWidth(), layer->getHeight());
LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
layer->getWidth(), layer->getHeight(), layer->getFbo());
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d570b0d..80b4c2a 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -42,6 +42,7 @@
#include "ShadowTessellator.h"
#include "SkiaShader.h"
#include "utils/GLUtils.h"
+#include "utils/TraceUtils.h"
#include "Vector.h"
#include "VertexBuffer.h"
@@ -51,21 +52,6 @@
#define EVENT_LOGD(...)
#endif
-static void atraceFormatBegin(const char* fmt, ...) {
- const int BUFFER_SIZE = 256;
- va_list ap;
- char buf[BUFFER_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, BUFFER_SIZE, fmt, ap);
- va_end(ap);
-
- ATRACE_BEGIN(buf);
-}
-
-#define ATRACE_FORMAT_BEGIN(fmt, ...) \
- if (CC_UNLIKELY(ATRACE_ENABLED())) atraceFormatBegin(fmt, ##__VA_ARGS__)
-
namespace android {
namespace uirenderer {
@@ -466,8 +452,6 @@
bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
if (layer->deferredUpdateScheduled && layer->renderer
&& layer->renderNode.get() && layer->renderNode->isRenderable()) {
- ATRACE_CALL();
-
Rect& dirty = layer->dirtyRect;
if (inFrame) {
@@ -525,20 +509,10 @@
int count = mLayerUpdates.size();
if (count > 0) {
startMark("Apply Layer Updates");
- char layerName[12];
// Note: it is very important to update the layers in order
for (int i = 0; i < count; i++) {
- Layer* layer = mLayerUpdates.itemAt(i).get();
-
- sprintf(layerName, "Layer #%d", i);
- startMark(layerName);
- ATRACE_FORMAT_BEGIN("flushLayer %ux%u", layer->getWidth(), layer->getHeight());
-
- layer->flush();
-
- ATRACE_END();
- endMark();
+ mLayerUpdates.itemAt(i)->flush();
}
mLayerUpdates.clear();
@@ -575,7 +549,7 @@
}
void OpenGLRenderer::flushLayerUpdates() {
- ATRACE_CALL();
+ ATRACE_NAME("Update HW Layers");
syncState();
updateLayers();
flushLayers();
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 9ba8854..6f48e4d 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -255,7 +255,7 @@
PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
const SkPaint* paint) {
- ATRACE_CALL();
+ ATRACE_NAME("Generate Path Texture");
float left, top, offset;
uint32_t width, height;
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 0dad0dc..e6fd2dc 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -132,7 +132,7 @@
}
GLuint Program::buildShader(const char* source, GLenum type) {
- ATRACE_CALL();
+ ATRACE_NAME("Build GL Shader");
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, 0);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 13c5499..eb0948f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -25,7 +25,6 @@
#include <SkCanvas.h>
#include <algorithm>
-#include <utils/Trace.h>
#include "DamageAccumulator.h"
#include "Debug.h"
@@ -34,6 +33,7 @@
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
+#include "utils/TraceUtils.h"
#include "renderthread/CanvasContext.h"
namespace android {
@@ -426,6 +426,10 @@
clipFlags = 0; // all clipping done by saveLayer
}
+ ATRACE_FORMAT("%s alpha caused %ssaveLayer %ux%u",
+ getName(), clipFlags ? "" : "unclipped ",
+ layerBounds.getWidth(), layerBounds.getHeight());
+
SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
properties().getAlpha() * 255, saveFlags);
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 3b8a9a4..5fcb194 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -26,6 +26,7 @@
#include "Caches.h"
#include "TextureCache.h"
#include "Properties.h"
+#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
@@ -266,7 +267,7 @@
return;
}
- ATRACE_CALL();
+ ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
// We could also enable mipmapping if both bitmap dimensions are powers
// of 2 but we'd have to deal with size changes. Let's keep this simple
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index ba878bac..af39f16 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -363,7 +363,7 @@
}
void Font::precache(const SkPaint* paint, const char* text, int numGlyphs) {
- ATRACE_NAME("precacheText");
+ ATRACE_NAME("Precache Glyphs");
if (numGlyphs == 0 || text == NULL) {
return;
diff --git a/libs/hwui/utils/TraceUtils.h b/libs/hwui/utils/TraceUtils.h
new file mode 100644
index 0000000..ff8ccb8
--- /dev/null
+++ b/libs/hwui/utils/TraceUtils.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef TRACE_UTILS_H
+#define TRACE_UTILS_H
+
+#include <utils/Trace.h>
+
+#define ATRACE_FORMAT(fmt, ...) \
+ TraceUtils::TraceEnder __traceEnder = (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+
+#define ATRACE_FORMAT_BEGIN(fmt, ...) \
+ TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+
+namespace android {
+namespace uirenderer {
+
+class TraceUtils {
+public:
+ class TraceEnder {
+ public:
+ ~TraceEnder() { ATRACE_END(); }
+ };
+
+ static void atraceFormatBegin(const char* fmt, ...) {
+ if (CC_UNLIKELY(!ATRACE_ENABLED())) return;
+
+ const int BUFFER_SIZE = 256;
+ va_list ap;
+ char buf[BUFFER_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ ATRACE_BEGIN(buf);
+ }
+
+}; // class TraceUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TRACE_UTILS_H */
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 7c0d758..a6cc493 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -35,4 +35,7 @@
public abstract void setStreamVolumeForUid(int streamType, int direction, int flags,
String callingPackage, int uid);
+
+ public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
+ int uid);
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 6e14aba..c70ac55 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -50,7 +50,6 @@
import android.media.MediaPlayer.OnErrorListener;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicyConfig;
-import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
@@ -61,7 +60,6 @@
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -75,12 +73,11 @@
import android.util.MathUtils;
import android.util.Slog;
import android.view.KeyEvent;
+import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
-import android.view.OrientationEventListener;
-import com.android.internal.telephony.ITelephony;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
@@ -91,8 +88,6 @@
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -100,6 +95,7 @@
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
/**
* The implementation of the volume manager service.
@@ -1152,6 +1148,10 @@
/** @see AudioManager#adjustMasterVolume(int, int) */
public void adjustMasterVolume(int steps, int flags, String callingPackage) {
+ adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
+ }
+
+ public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
if (mUseFixedVolume) {
return;
}
@@ -1166,7 +1166,7 @@
}
//Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
- setMasterVolume(volume, flags, callingPackage);
+ setMasterVolume(volume, flags, callingPackage, uid);
}
// StreamVolumeCommand contains the information needed to defer the process of
@@ -1679,18 +1679,24 @@
}
}
+ @Override
public int getMasterVolume() {
if (isMasterMute()) return 0;
return getLastAudibleMasterVolume();
}
+ @Override
public void setMasterVolume(int volume, int flags, String callingPackage) {
+ setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
+ }
+
+ public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
if (mUseFixedVolume) {
return;
}
- if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
+ != AppOpsManager.MODE_ALLOWED) {
return;
}
@@ -5667,6 +5673,12 @@
String callingPackage, int uid) {
setStreamVolume(streamType, direction, flags, callingPackage, uid);
}
+
+ @Override
+ public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
+ int uid) {
+ adjustMasterVolume(steps, flags, callingPackage, uid);
+ }
}
//==========================================================================================
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 924078c..754da0e 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -16,8 +16,6 @@
package android.media;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -25,16 +23,14 @@
import android.media.session.MediaController;
import android.net.Uri;
import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Size;
import android.util.SparseArray;
+import java.util.ArrayList;
import java.util.Set;
/**
@@ -569,6 +565,29 @@
}
/**
+ * Create a Builder using a {@link MediaMetadata} instance to set
+ * initial values, but replace bitmaps with a scaled down copy if they
+ * are larger than maxBitmapSize.
+ *
+ * @param source The original metadata to copy.
+ * @param maxBitmapSize The maximum height/width for bitmaps contained
+ * in the metadata.
+ * @hide
+ */
+ public Builder(MediaMetadata source, int maxBitmapSize) {
+ this(source);
+ for (String key : mBundle.keySet()) {
+ Object value = mBundle.get(key);
+ if (value != null && value instanceof Bitmap) {
+ Bitmap bmp = (Bitmap) value;
+ if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
+ putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
+ }
+ }
+ }
+ }
+
+ /**
* Put a CharSequence value into the metadata. Custom keys may be used,
* but if the METADATA_KEYs defined in this class are used they may only
* be one of the following:
@@ -707,6 +726,10 @@
* <li>{@link #METADATA_KEY_ALBUM_ART}</li>
* <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
* </ul>
+ * <p>
+ * Large bitmaps may be scaled down by the system. To pass full
+ * resolution images {@link Uri Uris} should be used with
+ * {@link #putString}.
*
* @param key The key for referencing this value
* @param value The Bitmap to store
@@ -731,5 +754,15 @@
public MediaMetadata build() {
return new MediaMetadata(mBundle);
}
+
+ private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
+ float maxSizeF = maxSize;
+ float widthScale = maxSizeF / bmp.getWidth();
+ float heightScale = maxSizeF / bmp.getHeight();
+ float scale = Math.min(widthScale, heightScale);
+ int height = (int) (bmp.getHeight() * scale);
+ int width = (int) (bmp.getWidth() * scale);
+ return Bitmap.createScaledBitmap(bmp, width, height, true);
+ }
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 973527f..e13f008 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -104,6 +104,7 @@
public @interface SessionFlags { }
private final Object mLock = new Object();
+ private final int mMaxBitmapSize;
private final MediaSession.Token mSessionToken;
private final MediaController mController;
@@ -147,6 +148,8 @@
if (TextUtils.isEmpty(tag)) {
throw new IllegalArgumentException("tag cannot be null or empty");
}
+ mMaxBitmapSize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
mCbStub = new CallbackStub(this);
MediaSessionManager manager = (MediaSessionManager) context
.getSystemService(Context.MEDIA_SESSION_SERVICE);
@@ -409,6 +412,7 @@
* @param metadata The new metadata
*/
public void setMetadata(@Nullable MediaMetadata metadata) {
+ metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
try {
mBinder.setMetadata(metadata);
} catch (RemoteException e) {
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index ef85847..4526af5 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -32,6 +32,7 @@
/>
<LinearLayout
+ android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
new file mode 100644
index 0000000..2ff8f8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Helper to invert the colors of views and fade between the states.
+ */
+public class ViewInvertHelper {
+
+ private final Paint mDarkPaint = new Paint();
+ private final Interpolator mLinearOutSlowInInterpolator;
+ private final View mTarget;
+ private final ColorMatrix mMatrix = new ColorMatrix();
+ private final ColorMatrix mGrayscaleMatrix = new ColorMatrix();
+ private final long mFadeDuration;
+
+ public ViewInvertHelper(View target, long fadeDuration) {
+ mTarget = target;
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(mTarget.getContext(),
+ android.R.interpolator.linear_out_slow_in);
+ mFadeDuration = fadeDuration;
+ }
+
+ public void fade(final boolean invert, long delay) {
+ float startIntensity = invert ? 0f : 1f;
+ float endIntensity = invert ? 1f : 0f;
+ ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateInvertPaint((Float) animation.getAnimatedValue());
+ mTarget.setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint);
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!invert) {
+ mTarget.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+ });
+ animator.setDuration(mFadeDuration);
+ animator.setInterpolator(mLinearOutSlowInInterpolator);
+ animator.setStartDelay(delay);
+ animator.start();
+ }
+
+ public void update(boolean invert) {
+ if (invert) {
+ updateInvertPaint(1f);
+ mTarget.setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint);
+ } else {
+ mTarget.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ public View getTarget() {
+ return mTarget;
+ }
+
+ private void updateInvertPaint(float intensity) {
+ float components = 1 - 2 * intensity;
+ final float[] invert = {
+ components, 0f, 0f, 0f, 255f * intensity,
+ 0f, components, 0f, 0f, 255f * intensity,
+ 0f, 0f, components, 0f, 255f * intensity,
+ 0f, 0f, 0f, 1f, 0f
+ };
+ mMatrix.set(invert);
+ mGrayscaleMatrix.setSaturation(1 - intensity);
+ mMatrix.preConcat(mGrayscaleMatrix);
+ mDarkPaint.setColorFilter(new ColorMatrixColorFilter(mMatrix));
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 02b9378..7b60307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -43,6 +43,7 @@
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -53,6 +54,7 @@
private static final long DOUBLETAP_TIMEOUT_MS = 1200;
private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
private static final int ACTIVATE_ANIMATION_LENGTH = 220;
+ private static final int DARK_ANIMATION_LENGTH = 170;
/**
* The amount of width, which is kept in the end when performing a disappear animation (also
@@ -84,6 +86,11 @@
*/
private static final float VERTICAL_ANIMATION_START = 1.0f;
+ /**
+ * Scale for the background to animate from when exiting dark mode.
+ */
+ private static final float DARK_EXIT_SCALE_START = 0.93f;
+
private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
= new PathInterpolator(0.6f, 0, 0.5f, 1);
private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
@@ -94,7 +101,6 @@
private boolean mDimmed;
private boolean mDark;
- private final Paint mDarkPaint = createDarkPaint();
private int mBgTint = 0;
private final int mRoundedRectCornerRadius;
@@ -332,40 +338,32 @@
if (mDimmed != dimmed) {
mDimmed = dimmed;
if (fade) {
- fadeBackground();
+ fadeDimmedBackground();
} else {
updateBackground();
}
}
}
- public void setDark(boolean dark, boolean fade) {
- // TODO implement fade
- if (mDark != dark) {
- mDark = dark;
- if (mDark) {
- setLayerType(View.LAYER_TYPE_HARDWARE, mDarkPaint);
- } else {
- setLayerType(View.LAYER_TYPE_NONE, null);
- }
+ public void setDark(boolean dark, boolean fade, long delay) {
+ super.setDark(dark, fade, delay);
+ if (mDark == dark) {
+ return;
}
- }
-
- private static Paint createDarkPaint() {
- final Paint p = new Paint();
- final float[] invert = {
- -1f, 0f, 0f, 1f, 1f,
- 0f, -1f, 0f, 1f, 1f,
- 0f, 0f, -1f, 1f, 1f,
- 0f, 0f, 0f, 1f, 0f
- };
- final ColorMatrix m = new ColorMatrix(invert);
- final ColorMatrix grayscale = new ColorMatrix();
- grayscale.setSaturation(0);
- m.preConcat(grayscale);
- p.setColorFilter(new ColorMatrixColorFilter(m));
- return p;
- }
+ mDark = dark;
+ if (!dark && fade) {
+ if (mActivated) {
+ mBackgroundDimmed.setVisibility(View.VISIBLE);
+ mBackgroundNormal.setVisibility(View.VISIBLE);
+ } else {
+ mBackgroundDimmed.setVisibility(View.VISIBLE);
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
+ }
+ fadeDarkToDimmed(delay);
+ } else {
+ updateBackground();
+ }
+ }
public void setShowingLegacyBackground(boolean showing) {
mShowingLegacyBackground = showing;
@@ -402,7 +400,39 @@
mBackgroundNormal.setRippleColor(rippleColor);
}
- private void fadeBackground() {
+ /**
+ * Fades the dimmed background when exiting dark mode.
+ */
+ private void fadeDarkToDimmed(long delay) {
+ mBackgroundDimmed.setAlpha(0f);
+ mBackgroundDimmed.setPivotX(mBackgroundDimmed.getWidth() / 2f);
+ mBackgroundDimmed.setPivotY(getActualHeight() / 2f);
+ mBackgroundDimmed.setScaleX(DARK_EXIT_SCALE_START);
+ mBackgroundDimmed.setScaleY(DARK_EXIT_SCALE_START);
+ mBackgroundDimmed.animate()
+ .alpha(1f)
+ .scaleX(1f)
+ .scaleY(1f)
+ .setDuration(DARK_ANIMATION_LENGTH)
+ .setStartDelay(delay)
+ .setInterpolator(mLinearOutSlowInInterpolator)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ // Jump state if we are cancelled
+ mBackgroundDimmed.setScaleX(1f);
+ mBackgroundDimmed.setScaleY(1f);
+ mBackgroundDimmed.setAlpha(1f);
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Fades the background when the dimmed state changes.
+ */
+ private void fadeDimmedBackground() {
+ mBackgroundDimmed.animate().cancel();
mBackgroundNormal.animate().cancel();
if (mDimmed) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
@@ -443,11 +473,14 @@
}
private void updateBackground() {
- if (mDimmed) {
+ cancelFadeAnimations();
+ if (mDark) {
+ mBackgroundDimmed.setVisibility(View.INVISIBLE);
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
+ } else if (mDimmed) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
mBackgroundNormal.setVisibility(View.INVISIBLE);
} else {
- cancelFadeAnimations();
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
mBackgroundNormal.setAlpha(1f);
@@ -459,6 +492,7 @@
if (mBackgroundAnimator != null) {
mBackgroundAnimator.cancel();
}
+ mBackgroundDimmed.animate().cancel();
mBackgroundNormal.animate().cancel();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7345440..8ad8406 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -207,11 +207,11 @@
}
@Override
- public void setDark(boolean dark, boolean fade) {
- super.setDark(dark, fade);
+ public void setDark(boolean dark, boolean fade, long delay) {
+ super.setDark(dark, fade, delay);
final NotificationContentView showing = getShowingLayout();
if (showing != null) {
- showing.setDark(dark, fade);
+ showing.setDark(dark, fade, delay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index bf1e78e..ebc663c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -39,6 +39,7 @@
private int mActualHeight;
protected int mClipTopAmount;
private boolean mActualHeightInitialized;
+ private boolean mDark;
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
public ExpandableView(Context context, AttributeSet attrs) {
@@ -185,8 +186,14 @@
*
* @param dark Whether the notification should be dark.
* @param fade Whether an animation should be played to change the state.
+ * @param delay If fading, the delay of the animation.
*/
- public void setDark(boolean dark, boolean fade) {
+ public void setDark(boolean dark, boolean fade, long delay) {
+ mDark = dark;
+ }
+
+ public boolean isDark() {
+ return mDark;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 99214a0..27da6fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -42,14 +42,14 @@
public class NotificationContentView extends FrameLayout {
private static final long ANIMATION_DURATION_LENGTH = 170;
- private static final Paint INVERT_PAINT = createInvertPaint();
- private static final ColorFilter NO_COLOR_FILTER = new ColorFilter();
private final Rect mClipBounds = new Rect();
private View mContractedChild;
private View mExpandedChild;
+ private NotificationViewWrapper mContractedWrapper;
+
private int mSmallHeight;
private int mClipTopAmount;
private int mActualHeight;
@@ -84,8 +84,8 @@
}
@Override
- protected void onFinishInflate() {
- super.onFinishInflate();
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
updateVisibility();
}
@@ -122,6 +122,7 @@
sanitizeContractedLayoutParams(child);
addView(child);
mContractedChild = child;
+ mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
selectLayout(false /* animate */, true /* force */);
}
@@ -249,38 +250,10 @@
return mExpandedChild != null;
}
- public void setDark(boolean dark, boolean fade) {
+ public void setDark(boolean dark, boolean fade, long delay) {
if (mDark == dark || mContractedChild == null) return;
mDark = dark;
- setImageViewDark(dark, fade, com.android.internal.R.id.right_icon);
- setImageViewDark(dark, fade, com.android.internal.R.id.icon);
- }
-
- private void setImageViewDark(boolean dark, boolean fade, int imageViewId) {
- // TODO: implement fade
- final ImageView v = (ImageView) mContractedChild.findViewById(imageViewId);
- if (v == null) return;
- final Drawable d = v.getBackground();
- if (dark) {
- v.setLayerType(LAYER_TYPE_HARDWARE, INVERT_PAINT);
- if (d != null) {
- v.setTag(R.id.doze_saved_filter_tag, d.getColorFilter() != null ? d.getColorFilter()
- : NO_COLOR_FILTER);
- d.setColorFilter(getResources().getColor(R.color.doze_small_icon_background_color),
- PorterDuff.Mode.SRC_ATOP);
- v.setImageAlpha(getResources().getInteger(R.integer.doze_small_icon_alpha));
- }
- } else {
- v.setLayerType(LAYER_TYPE_NONE, null);
- if (d != null) {
- final ColorFilter filter = (ColorFilter) v.getTag(R.id.doze_saved_filter_tag);
- if (filter != null) {
- d.setColorFilter(filter == NO_COLOR_FILTER ? null : filter);
- v.setTag(R.id.doze_saved_filter_tag, null);
- }
- v.setImageAlpha(0xff);
- }
- }
+ mContractedWrapper.setDark(dark, fade, delay);
}
@Override
@@ -290,16 +263,4 @@
// layout, and saves us some layers.
return false;
}
-
- private static Paint createInvertPaint() {
- final Paint p = new Paint();
- final float[] invert = {
- -1f, 0f, 0f, 1f, 1f,
- 0f, -1f, 0f, 1f, 1f,
- 0f, 0f, -1f, 1f, 1f,
- 0f, 0f, 0f, 1f, 0f
- };
- p.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(invert)));
- return p;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java
new file mode 100644
index 0000000..045be3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.View;
+
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Wraps a notification containing a custom view.
+ */
+public class NotificationCustomViewWrapper extends NotificationViewWrapper {
+
+ private final ViewInvertHelper mInvertHelper;
+ private boolean mDark;
+
+ protected NotificationCustomViewWrapper(View view) {
+ super(view);
+ mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
+ }
+
+ @Override
+ public void setDark(boolean dark, boolean fade, long delay) {
+ if (mDark != dark) {
+ mDark = dark;
+ if (fade) {
+ mInvertHelper.fade(dark, delay);
+ } else {
+ mInvertHelper.update(dark);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaViewWrapper.java
new file mode 100644
index 0000000..8f63a79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaViewWrapper.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * Wraps a media notification.
+ */
+public class NotificationMediaViewWrapper extends NotificationTemplateViewWrapper {
+
+ private boolean mDark;
+
+ protected NotificationMediaViewWrapper(Context ctx, View view) {
+ super(ctx, view);
+ }
+
+ @Override
+ public void setDark(boolean dark, boolean fade, long delay) {
+ if (mDark != dark) {
+ mDark = dark;
+
+ // Only update the large icon, because the rest is already inverted.
+ setPictureGrayscale(dark, fade, delay);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index edfd205..bfa3aa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -21,6 +21,8 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
/**
* Container view for overflowing notification icons on Keyguard.
@@ -28,6 +30,8 @@
public class NotificationOverflowContainer extends ActivatableNotificationView {
private NotificationOverflowIconsView mIconsView;
+ private ViewInvertHelper mViewInvertHelper;
+ private boolean mDark;
public NotificationOverflowContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -39,6 +43,20 @@
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
mIconsView.setOverflowIndicator(findViewById(R.id.more_icon_overflow));
+ mViewInvertHelper = new ViewInvertHelper(findViewById(R.id.content),
+ NotificationPanelView.DOZE_ANIMATION_DURATION);
+ }
+
+ @Override
+ public void setDark(boolean dark, boolean fade, long delay) {
+ super.setDark(dark, fade, delay);
+ if (mDark == dark) return;
+ mDark = dark;
+ if (fade) {
+ mViewInvertHelper.fade(dark, delay);
+ } else {
+ mViewInvertHelper.update(dark);
+ }
}
public NotificationOverflowIconsView getIconsView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
new file mode 100644
index 0000000..8dc14b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Wraps a notification view inflated from a template.
+ */
+public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
+
+ private final ViewInvertHelper mInvertHelper;
+ private final ImageView mIcon;
+ protected final ImageView mPicture;
+ private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
+ private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
+ 0, PorterDuff.Mode.SRC_ATOP);
+ private final int mIconDarkAlpha;
+ private final int mIconBackgroundColor;
+ private final int mIconBackgroundDarkColor;
+ private final Interpolator mLinearOutSlowInInterpolator;
+
+ private boolean mDark;
+
+ protected NotificationTemplateViewWrapper(Context ctx, View view) {
+ super(view);
+ mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+ mIconBackgroundDarkColor =
+ ctx.getResources().getColor(R.color.doze_small_icon_background_color);
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
+ android.R.interpolator.linear_out_slow_in);
+ View mainColumn = view.findViewById(com.android.internal.R.id.notification_main_column);
+ mInvertHelper = mainColumn != null
+ ? new ViewInvertHelper(mainColumn, NotificationPanelView.DOZE_ANIMATION_DURATION)
+ : null;
+ ImageView largeIcon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
+ ImageView rightIcon = (ImageView) view.findViewById(com.android.internal.R.id.right_icon);
+ mIcon = resolveIcon(largeIcon, rightIcon);
+ mPicture = resolvePicture(largeIcon);
+ mIconBackgroundColor = resolveBackgroundColor(mIcon);
+ }
+
+ private ImageView resolveIcon(ImageView largeIcon, ImageView rightIcon) {
+ return largeIcon != null && largeIcon.getBackground() != null ? largeIcon
+ : rightIcon != null && rightIcon.getBackground() != null ? rightIcon
+ : null;
+ }
+
+ private ImageView resolvePicture(ImageView largeIcon) {
+ return largeIcon != null && largeIcon.getBackground() == null
+ ? largeIcon
+ : null;
+ }
+
+ private int resolveBackgroundColor(ImageView icon) {
+ if (icon != null && icon.getBackground() != null) {
+ ColorFilter filter = icon.getBackground().getColorFilter();
+ if (filter instanceof PorterDuffColorFilter) {
+ return ((PorterDuffColorFilter) filter).getColor();
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public void setDark(boolean dark, boolean fade, long delay) {
+ if (mDark != dark) {
+ mDark = dark;
+ if (mInvertHelper != null) {
+ if (fade) {
+ mInvertHelper.fade(dark, delay);
+ } else {
+ mInvertHelper.update(dark);
+ }
+ }
+ if (mIcon != null) {
+ if (fade) {
+ fadeIconColorFilter(mIcon, dark, delay);
+ fadeIconAlpha(mIcon, dark, delay);
+ } else {
+ updateIconColorFilter(mIcon, dark);
+ updateIconAlpha(mIcon, dark);
+ }
+ }
+ setPictureGrayscale(dark, fade, delay);
+ }
+ }
+
+ protected void setPictureGrayscale(boolean grayscale, boolean fade, long delay) {
+ if (mPicture != null) {
+ if (fade) {
+ fadeGrayscale(mPicture, grayscale, delay);
+ } else {
+ updateGrayscale(mPicture, grayscale);
+ }
+ }
+ }
+
+ private void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+ boolean dark, long delay, Animator.AnimatorListener listener) {
+ float startIntensity = dark ? 0f : 1f;
+ float endIntensity = dark ? 1f : 0f;
+ ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+ animator.addUpdateListener(updateListener);
+ animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+ animator.setInterpolator(mLinearOutSlowInInterpolator);
+ animator.setStartDelay(delay);
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ animator.start();
+ }
+
+ private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateIconColorFilter(target, (Float) animation.getAnimatedValue());
+ }
+ }, dark, delay, null /* listener */);
+ }
+
+ private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = (float) animation.getAnimatedValue();
+ target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
+ }
+ }, dark, delay, null /* listener */);
+ }
+
+ protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateGrayscaleMatrix((float) animation.getAnimatedValue());
+ target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+ }
+ }, dark, delay, new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!dark) {
+ target.setColorFilter(null);
+ }
+ }
+ });
+ }
+
+ private void updateIconColorFilter(ImageView target, boolean dark) {
+ updateIconColorFilter(target, dark ? 1f : 0f);
+ }
+
+ private void updateIconColorFilter(ImageView target, float intensity) {
+ int color = interpolateColor(mIconBackgroundColor, mIconBackgroundDarkColor, intensity);
+ mIconColorFilter.setColor(color);
+ target.getBackground().mutate().setColorFilter(mIconColorFilter);
+ }
+
+ private void updateIconAlpha(ImageView target, boolean dark) {
+ target.setImageAlpha(dark ? mIconDarkAlpha : 255);
+ }
+
+ protected void updateGrayscale(ImageView target, boolean dark) {
+ if (dark) {
+ updateGrayscaleMatrix(1f);
+ target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+ } else {
+ target.setColorFilter(null);
+ }
+ }
+
+ private void updateGrayscaleMatrix(float intensity) {
+ mGrayscaleColorMatrix.setSaturation(1 - intensity);
+ }
+
+ private static int interpolateColor(int source, int target, float t) {
+ int aSource = Color.alpha(source);
+ int rSource = Color.red(source);
+ int gSource = Color.green(source);
+ int bSource = Color.blue(source);
+ int aTarget = Color.alpha(target);
+ int rTarget = Color.red(target);
+ int gTarget = Color.green(target);
+ int bTarget = Color.blue(target);
+ return Color.argb(
+ (int) (aSource * (1f - t) + aTarget * t),
+ (int) (rSource * (1f - t) + rTarget * t),
+ (int) (gSource * (1f - t) + gTarget * t),
+ (int) (bSource * (1f - t) + bTarget * t));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
new file mode 100644
index 0000000..0a02573
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * Wraps the actual notification content view; used to implement behaviors which are different for
+ * the individual templates and custom views.
+ */
+public abstract class NotificationViewWrapper {
+
+ protected final View mView;
+
+ public static NotificationViewWrapper wrap(Context ctx, View v) {
+
+ // TODO: Figure out a better way to find out which template the view is.
+ if (v.findViewById(com.android.internal.R.id.media_actions) != null) {
+ return new NotificationMediaViewWrapper(ctx, v);
+ } else if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
+ return new NotificationTemplateViewWrapper(ctx, v);
+ } else {
+ return new NotificationCustomViewWrapper(v);
+ }
+ }
+
+ protected NotificationViewWrapper(View view) {
+ mView = view;
+ }
+
+ /**
+ * In dark mode, we draw as little as possible, assuming a black background.
+ *
+ * @param dark whether we should display ourselves in dark mode
+ * @param fade whether to animate the transition if the mode changes
+ * @param delay if fading, the delay of the animation
+ */
+ public abstract void setDark(boolean dark, boolean fade, long delay);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9a1ac49..3fca56d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3708,14 +3708,11 @@
if (mState != StatusBarState.KEYGUARD && !mNotificationPanel.isDozing()) {
return;
}
- mNotificationPanel.setDozing(mDozing, mDozeScrimController.isPulsing() /*animate*/);
- if (mDozing) {
- mStackScroller.setDark(true, false /*animate*/);
- } else {
- mStackScroller.setDark(false, false /*animate*/);
- }
+ boolean animate = !mDozing && mDozeScrimController.isPulsing();
+ mNotificationPanel.setDozing(mDozing, animate);
+ mStackScroller.setDark(mDozing, animate);
mScrimController.setDozing(mDozing);
- mDozeScrimController.setDozing(mDozing, mDozeScrimController.isPulsing() /* animate */);
+ mDozeScrimController.setDozing(mDozing, animate);
}
public void updateStackScrollerState(boolean goingToFullShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 3c93b19..3d4cda6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -33,6 +33,7 @@
boolean animateHideSensitive;
boolean hasDelays;
boolean hasGoToFullShadeEvent;
+ boolean hasDarkEvent;
public AnimationFilter animateAlpha() {
animateAlpha = true;
@@ -98,6 +99,10 @@
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_GO_TO_FULL_SHADE) {
hasGoToFullShadeEvent = true;
}
+ if (events.get(i).animationType ==
+ NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_DARK) {
+ hasDarkEvent = true;
+ }
}
}
@@ -126,5 +131,6 @@
animateHideSensitive = false;
hasDelays = false;
hasGoToFullShadeEvent = false;
+ hasDarkEvent = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e63be97..c5f1161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2455,7 +2455,8 @@
// ANIMATION_TYPE_DARK
new AnimationFilter()
- .animateDark(),
+ .animateDark()
+ .hasDelays(),
// ANIMATION_TYPE_GO_TO_FULL_SHADE
new AnimationFilter()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 4611370..0b1ce8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -154,7 +154,7 @@
child.setDimmed(state.dimmed, false /* animate */);
// apply dark
- child.setDark(state.dark, false /* animate */);
+ child.setDark(state.dark, false /* animate */, 0 /* delay */);
// apply hiding sensitive
child.setHideSensitive(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index a56440c..05077bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -46,6 +46,7 @@
public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48;
+ public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24;
private static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
@@ -161,11 +162,12 @@
boolean scaleChanging = child.getScaleX() != viewState.scale;
boolean alphaChanging = alpha != child.getAlpha();
boolean heightChanging = viewState.height != child.getActualHeight();
+ boolean darkChanging = viewState.dark != child.isDark();
boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
boolean wasAdded = mNewAddChildren.contains(child);
boolean hasDelays = mAnimationFilter.hasDelays;
boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
- alphaChanging || heightChanging || topInsetChanging;
+ alphaChanging || heightChanging || topInsetChanging || darkChanging;
boolean noAnimation = wasAdded;
long delay = 0;
long duration = mCurrentLength;
@@ -242,7 +244,7 @@
&& !noAnimation);
// start dark animation
- child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation);
+ child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation, delay);
// apply speed bump state
child.setBelowSpeedBump(viewState.belowSpeedBump);
@@ -262,6 +264,9 @@
private long calculateChildAnimationDelay(StackScrollState.ViewState viewState,
StackScrollState finalState) {
+ if (mAnimationFilter.hasDarkEvent) {
+ return calculateDelayDark(viewState);
+ }
if (mAnimationFilter.hasGoToFullShadeEvent) {
return calculateDelayGoToFullShade(viewState);
}
@@ -309,6 +314,10 @@
return minDelay;
}
+ private long calculateDelayDark(StackScrollState.ViewState viewState) {
+ return viewState.notGoneIndex * ANIMATION_DELAY_PER_ELEMENT_DARK;
+ }
+
private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) {
float index = viewState.notGoneIndex;
index = (float) Math.pow(index, 0.7f);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fd54892..f0fb9e6 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -838,10 +838,12 @@
* indirect content-provider access.
*/
private class Identity {
- public int pid;
- public int uid;
+ public final IBinder token;
+ public final int pid;
+ public final int uid;
- Identity(int _pid, int _uid) {
+ Identity(IBinder _token, int _pid, int _uid) {
+ token = _token;
pid = _pid;
uid = _uid;
}
@@ -2275,15 +2277,19 @@
* process when the bindApplication() IPC is sent to the process. They're
* lazily setup to make sure the services are running when they're asked for.
*/
- private HashMap<String, IBinder> getCommonServicesLocked() {
+ private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
if (mAppBindArgs == null) {
- mAppBindArgs = new HashMap<String, IBinder>();
+ mAppBindArgs = new HashMap<>();
- // Setup the application init args
- mAppBindArgs.put("package", ServiceManager.getService("package"));
- mAppBindArgs.put("window", ServiceManager.getService("window"));
- mAppBindArgs.put(Context.ALARM_SERVICE,
- ServiceManager.getService(Context.ALARM_SERVICE));
+ // Isolated processes won't get this optimization, so that we don't
+ // violate the rules about which services they have access to.
+ if (!isolated) {
+ // Setup the application init args
+ mAppBindArgs.put("package", ServiceManager.getService("package"));
+ mAppBindArgs.put("window", ServiceManager.getService("window"));
+ mAppBindArgs.put(Context.ALARM_SERVICE,
+ ServiceManager.getService(Context.ALARM_SERVICE));
+ }
}
return mAppBindArgs;
}
@@ -5906,7 +5912,8 @@
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
- new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
+ new Configuration(mConfiguration), app.compat,
+ getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
@@ -6726,21 +6733,9 @@
*/
int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
- // We might be performing an operation on behalf of an indirect binder
- // invocation, e.g. via {@link #openContentUri}. Check and adjust the
- // client identity accordingly before proceeding.
- Identity tlsIdentity = sCallerIdentity.get();
- if (tlsIdentity != null) {
- Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
- + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
- uid = tlsIdentity.uid;
- pid = tlsIdentity.pid;
- }
-
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
-
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
@@ -6762,6 +6757,26 @@
return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
}
+ @Override
+ public int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken) {
+ if (permission == null) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ // We might be performing an operation on behalf of an indirect binder
+ // invocation, e.g. via {@link #openContentUri}. Check and adjust the
+ // client identity accordingly before proceeding.
+ Identity tlsIdentity = sCallerIdentity.get();
+ if (tlsIdentity != null && tlsIdentity.token == callerToken) {
+ Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
+ + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
+ uid = tlsIdentity.uid;
+ pid = tlsIdentity.pid;
+ }
+
+ return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
+ }
+
/**
* Binder IPC calls go through the public entry point.
* This can be called with or without the global lock held.
@@ -6967,13 +6982,13 @@
*/
@Override
public int checkUriPermission(Uri uri, int pid, int uid,
- final int modeFlags, int userId) {
+ final int modeFlags, int userId, IBinder callerToken) {
enforceNotIsolatedCaller("checkUriPermission");
// Another redirected-binder-call permissions check as in
- // {@link checkComponentPermission}.
+ // {@link checkPermissionWithToken}.
Identity tlsIdentity = sCallerIdentity.get();
- if (tlsIdentity != null) {
+ if (tlsIdentity != null && tlsIdentity.token == callerToken) {
uid = tlsIdentity.uid;
pid = tlsIdentity.pid;
}
@@ -9880,10 +9895,11 @@
// we do the check against the caller's permissions even though it looks
// to the content provider like the Activity Manager itself is making
// the request.
+ Binder token = new Binder();
sCallerIdentity.set(new Identity(
- Binder.getCallingPid(), Binder.getCallingUid()));
+ token, Binder.getCallingPid(), Binder.getCallingUid()));
try {
- pfd = cph.provider.openFile(null, uri, "r", null);
+ pfd = cph.provider.openFile(null, uri, "r", null, token);
} catch (FileNotFoundException e) {
// do nothing; pfd will be returned null
} finally {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 921b68b..9440697 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -90,6 +90,7 @@
private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService mService;
+ private final boolean mUseMasterVolume;
private final Object mLock = new Object();
private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
@@ -139,6 +140,8 @@
mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
+ mUseMasterVolume = service.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
}
/**
@@ -248,6 +251,12 @@
direction = -1;
}
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ if (mUseMasterVolume) {
+ // If this device only uses master volume and playback is local
+ // just adjust the master volume and return.
+ mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName, uid);
+ return;
+ }
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
if (useSuggested) {
if (AudioSystem.isStreamActive(stream, 0)) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index ba18f48..98a3970 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -86,6 +86,7 @@
private final Object mLock = new Object();
private final MessageHandler mHandler = new MessageHandler();
private final PowerManager.WakeLock mMediaEventWakeLock;
+ private final boolean mUseMasterVolume;
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
@@ -104,6 +105,8 @@
mPriorityStack = new MediaSessionStack();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+ mUseMasterVolume = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
}
@Override
@@ -819,8 +822,13 @@
return;
}
try {
- mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream, flags,
- getContext().getOpPackageName());
+ if (mUseMasterVolume) {
+ mAudioService.adjustMasterVolume(direction, flags,
+ getContext().getOpPackageName());
+ } else {
+ mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream, flags,
+ getContext().getOpPackageName());
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error adjusting default volume.", e);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f2d859f..7c03d42 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1797,10 +1797,9 @@
* for display purpose only, for example, displayed in Phone Status. It won't
* change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
* value.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
*
* @param alphaTag alpha-tagging of the dailing nubmer
* @param number The dialing number
@@ -1814,10 +1813,9 @@
* for display purpose only, for example, displayed in Phone Status. It won't
* change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
* value.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
*
* @param subId the subscriber that the alphatag and dialing number belongs to.
* @param alphaTag alpha-tagging of the dailing nubmer
@@ -1974,10 +1972,9 @@
/**
* Sets the voice mail number.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
*
* @param alphaTag The alpha tag to display.
* @param number The voicemail number.
@@ -1988,10 +1985,9 @@
/**
* Sets the voicemail number for the given subscriber.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
*
* @param subId The subscriber id.
* @param alphaTag The alpha tag to display.
@@ -3072,9 +3068,8 @@
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
* <p>
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
*
* @return true on success; false on any failure.
*/
@@ -3085,9 +3080,13 @@
/**
* Values used to return status for hasCarrierPrivileges call.
*/
+ /** @hide */
public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1;
+ /** @hide */
public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0;
+ /** @hide */
public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1;
+ /** @hide */
public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2;
/**
@@ -3099,21 +3098,18 @@
*
* TODO: Add a link to documentation.
*
- * @return CARRIER_PRIVILEGE_STATUS_HAS_ACCESS if the app has carrier privileges.
- * CARRIER_PRIVILEGE_STATUS_NO_ACCESS if the app does not have carrier privileges.
- * CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED if the carrier rules are not loaded.
- * CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES if there was an error loading carrier
- * rules (or if there are no rules).
+ * @return true if the app has carrier privileges.
*/
- public int hasCarrierPrivileges() {
+ public boolean hasCarrierPrivileges() {
try {
- return getITelephony().hasCarrierPrivileges();
+ return getITelephony().getCarrierPrivilegeStatus() ==
+ CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
} catch (RemoteException ex) {
Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
} catch (NullPointerException ex) {
Rlog.e(TAG, "hasCarrierPrivileges NPE", ex);
}
- return CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ return false;
}
/**
@@ -3124,9 +3120,8 @@
* brand value input. To unset the value, the same function should be
* called with a null brand value.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * or has to be carrier app - see #hasCarrierPrivileges.
+ * <p>Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
*
* @param brand The brand name to display/set.
* @return true if the operation was executed correctly.
@@ -3188,9 +3183,9 @@
try {
return getITelephony().checkCarrierPrivilegesForPackage(pkgname);
} catch (RemoteException ex) {
- Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
+ Rlog.e(TAG, "checkCarrierPrivilegesForPackage RemoteException", ex);
} catch (NullPointerException ex) {
- Rlog.e(TAG, "hasCarrierPrivileges NPE", ex);
+ Rlog.e(TAG, "checkCarrierPrivilegesForPackage NPE", ex);
}
return CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index cbfa9f6..adb3bc4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -713,7 +713,7 @@
*
* @return carrier privilege status defined in TelephonyManager.
*/
- int hasCarrierPrivileges();
+ int getCarrierPrivilegeStatus();
/**
* Similar to above, but check for pkg whose name is pkgname.
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 28d52b0..5ef71df 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -91,8 +91,8 @@
@Override
public ParcelFileDescriptor openFile(
- String callingPackage, Uri url, String mode, ICancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ String callingPackage, Uri url, String mode, ICancellationSignal signal,
+ IBinder callerToken) throws RemoteException, FileNotFoundException {
return MockContentProvider.this.openFile(url, mode);
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 46c81b6..3378872 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -37,6 +37,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.view.DisplayAdjustments;
@@ -483,6 +484,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ return checkPermission(permission, pid, uid);
+ }
+
@Override
public int checkCallingPermission(String permission) {
throw new UnsupportedOperationException();
@@ -524,6 +531,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
+ return checkUriPermission(uri, pid, uid, modeFlags);
+ }
+
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index c0dc7c3..ee8c376 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -62,7 +62,8 @@
}
public ParcelFileDescriptor openFile(
- String callingPackage, Uri url, String mode, ICancellationSignal signal) {
+ String callingPackage, Uri url, String mode, ICancellationSignal signal,
+ IBinder callerToken) {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 3930fd6..513f622 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -57,6 +57,16 @@
</service>
<receiver android:name="UserTarget">
</receiver>
+ <receiver android:name="StartEmpty" android:exported="true">
+ <intent-filter>
+ <action android:name="com.example.START_EMPTY" />
+ </intent-filter>
+ </receiver>
+ <service android:name="EmptyService" android:exported="true">
+ <intent-filter>
+ <action android:name="com.example.START_EMPTY" />
+ </intent-filter>
+ </service>
<receiver android:name="SingleUserReceiver"
android:singleUser="true" android:exported="true" >
</receiver>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/EmptyService.java b/tests/ActivityTests/src/com/google/android/test/activity/EmptyService.java
new file mode 100644
index 0000000..1134d90
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/EmptyService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activity;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+public class EmptyService extends Service {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i("StartEmpty", "STARTED!");
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/StartEmpty.java b/tests/ActivityTests/src/com/google/android/test/activity/StartEmpty.java
new file mode 100644
index 0000000..5e74ead
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/StartEmpty.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class StartEmpty extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i("StartEmpty", "STARTED!");
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 89288bf..e4cbb2f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -90,7 +90,7 @@
@Override
public ParcelFileDescriptor openFile(
- String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
+ String callingPackage, Uri arg0, String arg1, ICancellationSignal signal, IBinder token)
throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index aeb70e9..2c3736f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.android;
+import android.os.IBinder;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
@@ -938,12 +939,24 @@
}
@Override
+ public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
+ // pass
+ return 0;
+ }
+
+ @Override
public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
// pass
return 0;
}
@Override
+ public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) {
+ // pass
+ return 0;
+ }
+
+ @Override
public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
int arg4, int arg5) {
// pass