Merge "Animating the work profile button location now"
diff --git a/api/current.txt b/api/current.txt
index f13601e..cf2ea6d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4642,6 +4642,7 @@
method public android.content.Context getContext();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
+ method public android.app.UiAutomation getUiAutomation(int);
method public boolean invokeContextMenuAction(android.app.Activity, int, int);
method public boolean invokeMenuActionSync(android.app.Activity, int, int);
method public boolean isProfiling();
@@ -5538,6 +5539,7 @@
public final class UiAutomation {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
+ method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5554,6 +5556,7 @@
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+ field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
field public static final int ROTATION_FREEZE_180 = 2; // 0x2
field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -22496,6 +22499,7 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22574,6 +22578,7 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+ field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22890,7 +22895,7 @@
method public void onInputAdded(java.lang.String);
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
- method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22898,7 +22903,7 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
- method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+ method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -28536,6 +28541,10 @@
field public static final int OPEN = 32; // 0x20
}
+ public class FileUriExposedException extends java.lang.RuntimeException {
+ ctor public FileUriExposedException(java.lang.String);
+ }
+
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -29127,6 +29136,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 0d33503..6a420e2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4774,6 +4774,7 @@
method public android.content.Context getContext();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
+ method public android.app.UiAutomation getUiAutomation(int);
method public boolean invokeContextMenuAction(android.app.Activity, int, int);
method public boolean invokeMenuActionSync(android.app.Activity, int, int);
method public boolean isProfiling();
@@ -5670,6 +5671,7 @@
public final class UiAutomation {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
+ method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5686,6 +5688,7 @@
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+ field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
field public static final int ROTATION_FREEZE_180 = 2; // 0x2
field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -23837,6 +23840,7 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -23915,6 +23919,7 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+ field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -24405,7 +24410,7 @@
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
method public void onInputUpdated(java.lang.String);
- method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -24417,7 +24422,7 @@
method public java.lang.String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
method public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
method public java.lang.String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
- method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+ method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -30564,6 +30569,10 @@
field public static final int OPEN = 32; // 0x20
}
+ public class FileUriExposedException extends java.lang.RuntimeException {
+ ctor public FileUriExposedException(java.lang.String);
+ }
+
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -31163,6 +31172,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 48fd6f0..22eeef4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4642,6 +4642,7 @@
method public android.content.Context getContext();
method public android.content.Context getTargetContext();
method public android.app.UiAutomation getUiAutomation();
+ method public android.app.UiAutomation getUiAutomation(int);
method public boolean invokeContextMenuAction(android.app.Activity, int, int);
method public boolean invokeMenuActionSync(android.app.Activity, int, int);
method public boolean isProfiling();
@@ -5538,6 +5539,7 @@
public final class UiAutomation {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
+ method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5556,6 +5558,7 @@
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public android.graphics.Bitmap takeScreenshot();
method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+ field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
field public static final int ROTATION_FREEZE_0 = 0; // 0x0
field public static final int ROTATION_FREEZE_180 = 2; // 0x2
field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -22505,6 +22508,7 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22583,6 +22587,7 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+ field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22899,7 +22904,7 @@
method public void onInputAdded(java.lang.String);
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
- method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22907,7 +22912,7 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
- method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+ method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -28545,6 +28550,10 @@
field public static final int OPEN = 32; // 0x20
}
+ public class FileUriExposedException extends java.lang.RuntimeException {
+ ctor public FileUriExposedException(java.lang.String);
+ }
+
public class Handler {
ctor public Handler();
ctor public Handler(android.os.Handler.Callback);
@@ -29136,6 +29145,7 @@
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 11154f2..dc3f64a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4397,7 +4397,7 @@
String resolvedType = null;
if (fillInIntent != null) {
fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
+ fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -4629,7 +4629,7 @@
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
result = ActivityManagerNative.getDefault()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken,
@@ -4700,7 +4700,7 @@
if (mParent == null) {
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
return ActivityManagerNative.getDefault()
.startNextMatchingActivity(mToken, intent, options);
} catch (RemoteException e) {
@@ -5128,7 +5128,7 @@
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
try {
if (resultData != null) {
- resultData.prepareToLeaveProcess();
+ resultData.prepareToLeaveProcess(this);
}
if (ActivityManagerNative.getDefault()
.finishActivity(mToken, resultCode, resultData, finishTask)) {
@@ -5355,7 +5355,7 @@
@PendingIntent.Flags int flags) {
String packageName = getPackageName();
try {
- data.prepareToLeaveProcess();
+ data.prepareToLeaveProcess(this);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
@@ -6335,10 +6335,10 @@
resultData = mResultData;
}
if (resultData != null) {
- resultData.prepareToLeaveProcess();
+ resultData.prepareToLeaveProcess(this);
}
try {
- upIntent.prepareToLeaveProcess();
+ upIntent.prepareToLeaveProcess(this);
return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
resultCode, resultData);
} catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1e7457c..100e67b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -56,6 +56,7 @@
import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.DropBoxManager;
@@ -4959,16 +4960,22 @@
}
/**
- * For apps targetting SDK Honeycomb or later, we don't allow
- * network usage on the main event loop / UI thread.
- *
- * Note to those grepping: this is what ultimately throws
- * NetworkOnMainThreadException ...
+ * For apps targetting Honeycomb or later, we don't allow network usage
+ * on the main event loop / UI thread. This is what ultimately throws
+ * {@link NetworkOnMainThreadException}.
*/
- if (data.appInfo.targetSdkVersion > 9) {
+ if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
StrictMode.enableDeathOnNetwork();
}
+ /**
+ * For apps targetting N or later, we don't allow file:// Uri exposure.
+ * This is what ultimately throws {@link FileUriExposedException}.
+ */
+ if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+
NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(
(data.appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fab3740..0d6e93d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -752,7 +752,7 @@
String resolvedType = null;
if (fillInIntent != null) {
fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
+ fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -773,7 +773,7 @@
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
@@ -790,7 +790,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -805,7 +805,7 @@
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -822,7 +822,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -839,7 +839,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
@@ -856,7 +856,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -919,7 +919,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions, appOp,
@@ -933,7 +933,7 @@
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
@@ -955,7 +955,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
@@ -1006,7 +1006,7 @@
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions,
@@ -1022,7 +1022,7 @@
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
@@ -1058,7 +1058,7 @@
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1077,7 +1077,7 @@
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, getUserId());
} catch (RemoteException e) {
@@ -1090,7 +1090,7 @@
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
@@ -1105,7 +1105,7 @@
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
@@ -1140,7 +1140,7 @@
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1159,7 +1159,7 @@
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, user.getIdentifier());
} catch (RemoteException e) {
@@ -1262,7 +1262,7 @@
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
@@ -1291,7 +1291,7 @@
private boolean stopServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(this);
int res = ActivityManagerNative.getDefault().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1339,7 +1339,7 @@
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(this);
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 2caec369..7640e75 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -33,7 +33,7 @@
* {@hide}
*/
interface IUiAutomationConnection {
- void connect(IAccessibilityServiceClient client);
+ void connect(IAccessibilityServiceClient client, int flags);
void disconnect();
boolean injectInputEvent(in InputEvent event, boolean sync);
boolean setRotation(int rotation);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 24a3470..9a88f2c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1503,7 +1503,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1561,7 +1561,7 @@
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
intents[i].migrateExtraStreamToClipData();
- intents[i].prepareToLeaveProcess();
+ intents[i].prepareToLeaveProcess(who);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -1622,7 +1622,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1682,7 +1682,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivityAsUser(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1721,7 +1721,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = ActivityManagerNative.getDefault()
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1759,7 +1759,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(who);
int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
intent, intent.resolveTypeIfNeeded(who.getContentResolver()), options);
checkStartActivityResult(result, intent);
@@ -1837,16 +1837,59 @@
* {@link Instrumentation} APIs. Using both APIs at the same time is not
* a mistake by itself but a client has to be aware of the APIs limitations.
* </p>
- * @return The UI automation instance.
+ * @return The UI automation instance. If none exists, a new one is created with no flags set.
*
* @see UiAutomation
*/
public UiAutomation getUiAutomation() {
if (mUiAutomationConnection != null) {
if (mUiAutomation == null) {
+ return getUiAutomation(0);
+ }
+ return mUiAutomation;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the {@link UiAutomation} instance with flags set.
+ * <p>
+ * <strong>Note:</strong> Only one UiAutomation can be obtained. Calling this method
+ * twice with different flags will fail unless the UiAutomation obtained in the first call
+ * is released with {@link UiAutomation#destroy()}.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation}
+ * work across application boundaries while the APIs exposed by the instrumentation
+ * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will
+ * not allow you to inject the event in an app different from the instrumentation
+ * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)}
+ * will work regardless of the current application.
+ * </p>
+ * <p>
+ * A typical test case should be using either the {@link UiAutomation} or
+ * {@link Instrumentation} APIs. Using both APIs at the same time is not
+ * a mistake by itself but a client has to be aware of the APIs limitations.
+ * </p>
+ *
+ * @param flags The flags to be passed to the UiAutomation, for example
+ * {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}.
+ *
+ * @return The UI automation instance.
+ *
+ * @see UiAutomation
+ */
+ public UiAutomation getUiAutomation(int flags) {
+ if (mUiAutomationConnection != null) {
+ if ((mUiAutomation == null) || (mUiAutomation.isDestroyed())) {
mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(),
mUiAutomationConnection);
- mUiAutomation.connect();
+ mUiAutomation.connect(flags);
+ } else {
+ if (mUiAutomation.getFlags() != flags) {
+ throw new RuntimeException(
+ "Cannot get a UiAutomation with different flags from the existing one");
+ }
}
return mUiAutomation;
}
@@ -1861,8 +1904,8 @@
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
} catch (RuntimeException e) {
- Log.w(TAG, "Exception setting priority of instrumentation thread "
- + Process.myTid(), e);
+ Log.w(TAG, "Exception setting priority of instrumentation thread "
+ + Process.myTid(), e);
}
if (mAutomaticPerformanceSnapshots) {
startPerformanceSnapshot();
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index edafe59..412b098 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -307,7 +307,7 @@
context.getContentResolver()) : null;
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -332,7 +332,7 @@
context.getContentResolver()) : null;
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -446,7 +446,7 @@
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
intents[i].migrateExtraStreamToClipData();
- intents[i].prepareToLeaveProcess();
+ intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -472,7 +472,7 @@
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
intents[i].migrateExtraStreamToClipData();
- intents[i].prepareToLeaveProcess();
+ intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -527,7 +527,7 @@
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -570,7 +570,7 @@
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index dce2e51..79d383c 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -105,6 +105,14 @@
/** Rotation constant: Freeze rotation to 270 degrees . */
public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
+ /**
+ * UiAutomation supresses accessibility services by default. This flag specifies that
+ * existing accessibility services should continue to run, and that new ones may start.
+ * This flag is set when obtaining the UiAutomation from
+ * {@link Instrumentation#getUiAutomation(int)}.
+ */
+ public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 0x00000001;
+
private final Object mLock = new Object();
private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<AccessibilityEvent>();
@@ -123,6 +131,10 @@
private boolean mIsConnecting;
+ private boolean mIsDestroyed;
+
+ private int mFlags;
+
/**
* Listener for observing the {@link AccessibilityEvent} stream.
*/
@@ -182,11 +194,22 @@
}
/**
- * Connects this UiAutomation to the accessibility introspection APIs.
+ * Connects this UiAutomation to the accessibility introspection APIs with default flags.
*
* @hide
*/
public void connect() {
+ connect(0);
+ }
+
+ /**
+ * Connects this UiAutomation to the accessibility introspection APIs.
+ *
+ * @param flags Any flags to apply to the automation as it gets connected
+ *
+ * @hide
+ */
+ public void connect(int flags) {
synchronized (mLock) {
throwIfConnectedLocked();
if (mIsConnecting) {
@@ -197,7 +220,8 @@
try {
// Calling out without a lock held.
- mUiAutomationConnection.connect(mClient);
+ mUiAutomationConnection.connect(mClient, flags);
+ mFlags = flags;
} catch (RemoteException re) {
throw new RuntimeException("Error while connecting UiAutomation", re);
}
@@ -227,6 +251,17 @@
}
/**
+ * Get the flags used to connect the service.
+ *
+ * @return The flags used to connect
+ *
+ * @hide
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
* Disconnects this UiAutomation from the accessibility introspection APIs.
*
* @hide
@@ -263,6 +298,17 @@
}
/**
+ * Reports if the object has been destroyed
+ *
+ * @return {code true} if the object has been destroyed.
+ *
+ * @hide
+ */
+ public boolean isDestroyed() {
+ return mIsDestroyed;
+ }
+
+ /**
* Sets a callback for observing the stream of {@link AccessibilityEvent}s.
*
* @param listener The callback.
@@ -274,6 +320,15 @@
}
/**
+ * Destroy this UiAutomation. After calling this method, attempting to use the object will
+ * result in errors.
+ */
+ public void destroy() {
+ disconnect();
+ mIsDestroyed = true;
+ }
+
+ /**
* Performs a global action. Such an action can be performed at any moment
* regardless of the current application or user location in that application.
* For example going back, going home, opening recents, etc.
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index bd10267..276f774 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -77,7 +77,7 @@
private int mOwningUid;
- public void connect(IAccessibilityServiceClient client) {
+ public void connect(IAccessibilityServiceClient client, int flags) {
if (client == null) {
throw new IllegalArgumentException("Client cannot be null!");
}
@@ -87,7 +87,7 @@
throw new IllegalStateException("Already connected.");
}
mOwningUid = Binder.getCallingUid();
- registerUiTestAutomationServiceLocked(client);
+ registerUiTestAutomationServiceLocked(client, flags);
storeRotationStateLocked();
}
}
@@ -322,7 +322,8 @@
}
}
- private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client) {
+ private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client,
+ int flags) {
IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
@@ -337,7 +338,7 @@
try {
// Calling out with a lock held is fine since if the system
// process is gone the client calling in will be killed.
- manager.registerUiTestAutomationService(mToken, client, info);
+ manager.registerUiTestAutomationService(mToken, client, info, flags);
mClient = client;
} catch (RemoteException re) {
throw new IllegalStateException("Error while registering UiTestAutomationService.", re);
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 2260d7e..10e6fb2 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -522,7 +522,7 @@
IActivityManager am = ActivityManagerNative.getDefault();
IBinder binder = null;
try {
- service.prepareToLeaveProcess();
+ service.prepareToLeaveProcess(myContext);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 6dfefac..0ec58ea 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -823,14 +823,14 @@
*
* @hide
*/
- public void prepareToLeaveProcess() {
+ public void prepareToLeaveProcess(boolean leavingPackage) {
final int size = mItems.size();
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
- item.mIntent.prepareToLeaveProcess();
+ item.mIntent.prepareToLeaveProcess(leavingPackage);
}
- if (item.mUri != null && StrictMode.vmFileUriExposureEnabled()) {
+ if (item.mUri != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
}
}
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 5653cad..e67da2b 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -118,7 +118,7 @@
public void setPrimaryClip(ClipData clip) {
try {
if (clip != null) {
- clip.prepareToLeaveProcess();
+ clip.prepareToLeaveProcess(true);
}
getService().setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 49b8363..ee469da 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8912,23 +8912,46 @@
*
* @hide
*/
- public void prepareToLeaveProcess() {
+ public void prepareToLeaveProcess(Context context) {
+ final boolean leavingPackage = (mComponent == null)
+ || !Objects.equals(mComponent.getPackageName(), context.getPackageName());
+ prepareToLeaveProcess(leavingPackage);
+ }
+
+ /**
+ * Prepare this {@link Intent} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveProcess(boolean leavingPackage) {
setAllowFds(false);
if (mSelector != null) {
- mSelector.prepareToLeaveProcess();
+ mSelector.prepareToLeaveProcess(leavingPackage);
}
if (mClipData != null) {
- mClipData.prepareToLeaveProcess();
+ mClipData.prepareToLeaveProcess(leavingPackage);
}
- if (mData != null && StrictMode.vmFileUriExposureEnabled()) {
- // There are several ACTION_MEDIA_* broadcasts that send file://
- // Uris, so only check common actions.
- if (ACTION_VIEW.equals(mAction) ||
- ACTION_EDIT.equals(mAction) ||
- ACTION_ATTACH_DATA.equals(mAction)) {
- mData.checkFileUriExposed("Intent.getData()");
+ if (mData != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
+ switch (mAction) {
+ case ACTION_MEDIA_REMOVED:
+ case ACTION_MEDIA_UNMOUNTED:
+ case ACTION_MEDIA_CHECKING:
+ case ACTION_MEDIA_NOFS:
+ case ACTION_MEDIA_MOUNTED:
+ case ACTION_MEDIA_SHARED:
+ case ACTION_MEDIA_UNSHARED:
+ case ACTION_MEDIA_BAD_REMOVAL:
+ case ACTION_MEDIA_UNMOUNTABLE:
+ case ACTION_MEDIA_EJECT:
+ case ACTION_MEDIA_SCANNER_STARTED:
+ case ACTION_MEDIA_SCANNER_FINISHED:
+ case ACTION_MEDIA_SCANNER_SCAN_FILE:
+ // Ignore legacy actions
+ break;
+ default:
+ mData.checkFileUriExposed("Intent.getData()");
}
}
}
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index 584008c..2cafa08 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -16,8 +16,10 @@
package android.hardware.input;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.LocaleList;
import java.util.Locale;
@@ -32,7 +34,8 @@
private final String mLabel;
private final String mCollection;
private final int mPriority;
- private final Locale[] mLocales;
+ @NonNull
+ private final LocaleList mLocales;
private final int mVendorId;
private final int mProductId;
@@ -47,16 +50,12 @@
};
public KeyboardLayout(String descriptor, String label, String collection, int priority,
- Locale[] locales, int vid, int pid) {
+ LocaleList locales, int vid, int pid) {
mDescriptor = descriptor;
mLabel = label;
mCollection = collection;
mPriority = priority;
- if (locales != null) {
- mLocales = locales;
- } else {
- mLocales = new Locale[0];
- }
+ mLocales = locales;
mVendorId = vid;
mProductId = pid;
}
@@ -66,11 +65,7 @@
mLabel = source.readString();
mCollection = source.readString();
mPriority = source.readInt();
- int N = source.readInt();
- mLocales = new Locale[N];
- for (int i = 0; i < N; i++) {
- mLocales[i] = Locale.forLanguageTag(source.readString());
- }
+ mLocales = LocaleList.CREATOR.createFromParcel(source);
mVendorId = source.readInt();
mProductId = source.readInt();
}
@@ -108,7 +103,7 @@
* This may be empty if a locale has not been assigned to this keyboard layout.
* @return The keyboard layout's intended locale.
*/
- public Locale[] getLocales() {
+ public LocaleList getLocales() {
return mLocales;
}
@@ -141,14 +136,7 @@
dest.writeString(mLabel);
dest.writeString(mCollection);
dest.writeInt(mPriority);
- if (mLocales != null) {
- dest.writeInt(mLocales.length);
- for (Locale l : mLocales) {
- dest.writeString(l.toLanguageTag());
- }
- } else {
- dest.writeInt(0);
- }
+ mLocales.writeToParcel(dest, 0);
dest.writeInt(mVendorId);
dest.writeInt(mProductId);
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 4a8dfbc..53b027b 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -2343,7 +2343,7 @@
*/
public void checkFileUriExposed(String location) {
if ("file".equals(getScheme())) {
- StrictMode.onFileUriExposed(location);
+ StrictMode.onFileUriExposed(this, location);
}
}
diff --git a/core/java/android/os/FileUriExposedException.java b/core/java/android/os/FileUriExposedException.java
new file mode 100644
index 0000000..e47abe2
--- /dev/null
+++ b/core/java/android/os/FileUriExposedException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.content.Intent;
+
+/**
+ * The exception that is thrown when an application exposes a {@code file://}
+ * {@link android.net.Uri} to another app.
+ * <p>
+ * This exposure is discouraged since the receiving app may not have access to
+ * the shared path. For example, the receiving app may not have requested the
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime permission,
+ * or the platform may be sharing the {@link android.net.Uri} across user
+ * profile boundaries.
+ * <p>
+ * Instead, apps should use {@code content://} Uris so the platform can extend
+ * temporary permission for the receiving app to access the resource.
+ * <p>
+ * This is only thrown for applications targeting {@link Build.VERSION_CODES#N}
+ * or higher. Applications targeting earlier SDK versions are allowed to share
+ * {@code file://} {@link android.net.Uri}, but it's strongly discouraged.
+ *
+ * @see android.support.v4.content.FileProvider
+ * @see Intent#FLAG_GRANT_READ_URI_PERMISSION
+ */
+public class FileUriExposedException extends RuntimeException {
+ public FileUriExposedException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f1672df..91d88da 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.net.Uri;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Printer;
@@ -46,7 +47,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -243,42 +243,15 @@
// Byte 3: Penalty
- /**
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
-
- // Used for both process and thread policy:
-
- /**
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_DIALOG = 0x02 << 16;
-
- /**
- * Death on any detected violation.
- *
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_DEATH = 0x04 << 16;
-
- /**
- * Death just for detected network usage.
- *
- * @hide
- */
- public static final int PENALTY_DEATH_ON_NETWORK = 0x08 << 16;
-
- /**
- * Flash the screen during violations.
- *
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_FLASH = 0x10 << 16;
-
- /**
- * @hide
- */
+ /** {@hide} */
public static final int PENALTY_DROPBOX = 0x20 << 16;
/**
@@ -294,12 +267,28 @@
*/
public static final int PENALTY_GATHER = 0x40 << 16;
+ // Byte 4: Special cases
+
+ /**
+ * Death when network traffic is detected on main thread.
+ *
+ * @hide
+ */
+ public static final int PENALTY_DEATH_ON_NETWORK = 0x01 << 24;
+
/**
* Death when cleartext network traffic is detected.
*
* @hide
*/
- public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x80 << 16;
+ public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x02 << 24;
+
+ /**
+ * Death when file exposure is detected.
+ *
+ * @hide
+ */
+ public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
/**
* Mask of all the penalty bits valid for thread policies.
@@ -312,7 +301,7 @@
* Mask of all the penalty bits valid for VM policies.
*/
private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX
- | PENALTY_DEATH_ON_CLEARTEXT_NETWORK;
+ | PENALTY_DEATH_ON_CLEARTEXT_NETWORK | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
/** {@hide} */
public static final int NETWORK_POLICY_ACCEPT = 0;
@@ -748,10 +737,22 @@
}
/**
- * Detect when a {@code file://} {@link android.net.Uri} is exposed beyond this
- * app. The receiving app may not have access to the sent path.
- * Instead, when sharing files between apps, {@code content://}
- * should be used with permission grants.
+ * Detect when this application exposes a {@code file://}
+ * {@link android.net.Uri} to another app.
+ * <p>
+ * This exposure is discouraged since the receiving app may not have
+ * access to the shared path. For example, the receiving app may not
+ * have requested the
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime
+ * permission, or the platform may be sharing the
+ * {@link android.net.Uri} across user profile boundaries.
+ * <p>
+ * Instead, apps should use {@code content://} Uris so the platform
+ * can extend temporary permission for the receiving app to access
+ * the resource.
+ *
+ * @see android.support.v4.content.FileProvider
+ * @see Intent#FLAG_GRANT_READ_URI_PERMISSION
*/
public Builder detectFileUriExposure() {
return enable(DETECT_VM_FILE_URI_EXPOSURE);
@@ -798,6 +799,16 @@
}
/**
+ * Crashes the whole process when a {@code file://}
+ * {@link android.net.Uri} is exposed beyond this app.
+ *
+ * @see #detectFileUriExposure()
+ */
+ public Builder penaltyDeathOnFileUriExposure() {
+ return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
+ }
+
+ /**
* Log detected violations to the system log.
*/
public Builder penaltyLog() {
@@ -1111,6 +1122,25 @@
}
/**
+ * Used by the framework to make file usage a fatal error.
+ *
+ * @hide
+ */
+ public static void enableDeathOnFileUriExposure() {
+ sVmPolicyMask |= DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
+ }
+
+ /**
+ * Used by lame internal apps that haven't done the hard work to get
+ * themselves off file:// Uris yet.
+ *
+ * @hide
+ */
+ public static void disableDeathOnFileUriExposure() {
+ sVmPolicyMask &= ~(DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
+ }
+
+ /**
* Parses the BlockGuard policy mask out from the Exception's
* getMessage() String value. Kinda gross, but least
* invasive. :/
@@ -1755,9 +1785,13 @@
/**
* @hide
*/
- public static void onFileUriExposed(String location) {
- final String message = "file:// Uri exposed through " + location;
- onVmPolicyViolation(null, new Throwable(message));
+ public static void onFileUriExposed(Uri uri, String location) {
+ final String message = uri + " exposed beyond app through " + location;
+ if ((sVmPolicyMask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
+ throw new FileUriExposedException(message);
+ } else {
+ onVmPolicyViolation(null, new Throwable(message));
+ }
}
/**
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 0c6a0c6..6ff9fe7 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1170,7 +1170,7 @@
}
try {
intent.migrateExtraStreamToClipData();
- intent.prepareToLeaveProcess();
+ intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startVoiceActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()));
Instrumentation.checkStartActivityResult(res, intent);
diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java
index 013255b..57d07c0 100644
--- a/core/java/android/view/KeyboardShortcutGroup.java
+++ b/core/java/android/view/KeyboardShortcutGroup.java
@@ -32,6 +32,8 @@
public final class KeyboardShortcutGroup implements Parcelable {
private final CharSequence mLabel;
private final List<KeyboardShortcutInfo> mItems;
+ // The system group looks different UI wise.
+ private boolean mSystemGroup;
/**
* @param label The title to be used for this group, or null if there is none.
@@ -50,10 +52,33 @@
this(label, Collections.<KeyboardShortcutInfo>emptyList());
}
+ /**
+ * @param label The title to be used for this group, or null if there is none.
+ * @param items The set of items to be included.
+ * @param isSystemGroup Set this to {@code true} if this is s system group.
+ * @hide
+ */
+ public KeyboardShortcutGroup(@Nullable CharSequence label,
+ @NonNull List<KeyboardShortcutInfo> items, boolean isSystemGroup) {
+ mLabel = label;
+ mItems = new ArrayList<>(checkNotNull(items));
+ mSystemGroup = isSystemGroup;
+ }
+
+ /**
+ * @param label The title to be used for this group, or null if there is none.
+ * @param isSystemGroup Set this to {@code true} if this is s system group.
+ * @hide
+ */
+ public KeyboardShortcutGroup(@Nullable CharSequence label, boolean isSystemGroup) {
+ this(label, Collections.<KeyboardShortcutInfo>emptyList(), isSystemGroup);
+ }
+
private KeyboardShortcutGroup(Parcel source) {
mItems = new ArrayList<>();
mLabel = source.readCharSequence();
source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR);
+ mSystemGroup = source.readInt() == 1;
}
/**
@@ -70,6 +95,11 @@
return mItems;
}
+ /** @hide **/
+ public boolean isSystemGroup() {
+ return mSystemGroup;
+ }
+
/**
* Adds an item to the existing list.
*
@@ -88,6 +118,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mLabel);
dest.writeTypedList(mItems);
+ dest.writeInt(mSystemGroup ? 1 : 0);
}
public static final Creator<KeyboardShortcutGroup> CREATOR =
@@ -99,4 +130,4 @@
return new KeyboardShortcutGroup[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7ba046b..81bb638 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -139,9 +139,7 @@
private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL);
private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
-
- /** @hide */
- public static boolean sUseLargeIcons = false;
+ private static boolean sUseLargeIcons = false;
private final int mStyle;
private int mSystemIconResourceId;
@@ -235,6 +233,15 @@
}
/**
+ * Updates wheter accessibility large icons are used or not.
+ * @hide
+ */
+ public static void setUseLargeIcons(boolean use) {
+ sUseLargeIcons = use;
+ gSystemIcons.clear();
+ }
+
+ /**
* Creates a custom pointer from the given bitmap and hotspot information.
*
* @param bitmap The bitmap for the icon.
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 9e79057..655c9b3 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -51,7 +51,7 @@
void removeAccessibilityInteractionConnection(IWindow windowToken);
void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient client,
- in AccessibilityServiceInfo info);
+ in AccessibilityServiceInfo info, int flags);
void unregisterUiTestAutomationService(IAccessibilityServiceClient client);
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b2eab4c..26421fb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4191,10 +4191,10 @@
<string name="new_sms_notification_content">Open SMS app to view</string>
<!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_title">Device encrypted</string>
+ <string name="user_encrypted_title">Some functions might not be available</string>
<!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_message">Some functions might not be available</string>
+ <string name="user_encrypted_message">Touch to continue</string>
<!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_detail">Touch to continue</string>
+ <string name="user_encrypted_detail">User profile locked</string>
</resources>
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b1a51a56..3d9b60d 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -605,6 +605,7 @@
/**
* Request that the player start playback for a specific media id.
*
+ * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param mediaId The id of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
@@ -626,6 +627,7 @@
* An empty or null query should be treated as a request to play any
* music.
*
+ * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param query The search query.
* @param extras Optional extras that can include extra information
* about the query.
@@ -646,6 +648,7 @@
/**
* Request that the player start playback for a specific {@link Uri}.
*
+ * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param uri The URI of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e1e9b79..8c5b19c 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,6 +87,12 @@
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
+ * Set this flag on the session to indicate that it can handle
+ * the {@link PlaybackState#EXTRA_PREPARE_ONLY} field.
+ */
+ public static final int FLAG_HANDLES_PREPARE_ONLY = 1 << 2;
+
+ /**
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
@@ -100,6 +106,7 @@
@IntDef(flag = true, value = {
FLAG_HANDLES_MEDIA_BUTTONS,
FLAG_HANDLES_TRANSPORT_CONTROLS,
+ FLAG_HANDLES_PREPARE_ONLY,
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index bbe04b5..1079a1f 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -133,6 +133,21 @@
public static final long ACTION_PLAY_FROM_URI = 1 << 13;
/**
+ * Used as an optional boolean extra field in
+ * {@link MediaController.TransportControls#playFromMediaId},
+ * {@link MediaController.TransportControls#playFromSearch}, and
+ * {@link MediaController.TransportControls#playFromUri}. Value of {@code true} overrides
+ * the default behavior of starting the playback after preparing. Check
+ * {@link MediaSession#FLAG_HANDLES_PREPARE_ONLY} to see if the media session supports this.
+ *
+ * @see MediaSession#FLAG_HANDLES_PREPARE_ONLY
+ * @see MediaController.TransportControls#playFromMediaId
+ * @see MediaController.TransportControls#playFromSearch
+ * @see MediaController.TransportControls#playFromUri
+ */
+ public static final String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
+
+ /**
* This is the default playback state and indicates that no media has been
* added yet, or the performer has been reset and has no content to play.
*
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 0febc16..d189333 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -41,6 +41,7 @@
interface ITvInputManager {
List<TvInputInfo> getTvInputList(int userId);
TvInputInfo getTvInputInfo(in String inputId, int userId);
+ void setTvInputInfo(in TvInputInfo inputInfo, int userId);
int getTvInputState(in String inputId, int userId);
List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
diff --git a/media/java/android/media/tv/ITvInputManagerCallback.aidl b/media/java/android/media/tv/ITvInputManagerCallback.aidl
index 3bf415b..395c9f3 100644
--- a/media/java/android/media/tv/ITvInputManagerCallback.aidl
+++ b/media/java/android/media/tv/ITvInputManagerCallback.aidl
@@ -29,5 +29,5 @@
void onInputStateChanged(in String inputId, int state);
- void onTvInputInfoChanged(in String inputId, in TvInputInfo TvInputInfo);
+ void onTvInputInfoChanged(in TvInputInfo TvInputInfo);
}
diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
index 9f13882..74ab562 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -27,6 +27,4 @@
void addHardwareTvInput(in int deviceId, in TvInputInfo inputInfo);
void addHdmiTvInput(in int id, in TvInputInfo inputInfo);
void removeTvInput(in String inputId);
-
- void setTvInputInfo(in String inputId, in TvInputInfo inputInfo);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f1de8fd..86bded9 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -726,12 +726,11 @@
}
/**
- * This is called when the information about a given TV input is changed.
+ * This is called when the information about a given TV input has been changed.
*
- * @param inputId The ID of the TV input.
* @param inputInfo TvInputInfo object that contains the information about the TV input.
*/
- public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) {
+ public void onTvInputInfoChanged(TvInputInfo inputInfo) {
}
}
@@ -784,11 +783,11 @@
});
}
- public void postTvInputInfoChanged(final String inputId, final TvInputInfo inputInfo) {
+ public void postTvInputInfoChanged(final TvInputInfo inputInfo) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onTvInputInfoChanged(inputId, inputInfo);
+ mCallback.onTvInputInfoChanged(inputInfo);
}
});
}
@@ -1089,10 +1088,10 @@
}
@Override
- public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) {
+ public void onTvInputInfoChanged(TvInputInfo inputInfo) {
synchronized (mLock) {
for (TvInputCallbackRecord record : mCallbackRecords) {
- record.postTvInputInfoChanged(inputId, inputInfo);
+ record.postTvInputInfoChanged(inputInfo);
}
}
}
@@ -1143,6 +1142,23 @@
}
/**
+ * Sets a new TvInputInfo object for a given input.
+ *
+ * <p>This is called internally only by {@link TvInputService}.
+ *
+ * @param inputInfo The TvInputInfo object to set.
+ * @throws IllegalArgumentException if the argument is {@code null}.
+ */
+ void setTvInputInfo(@NonNull TvInputInfo inputInfo) {
+ Preconditions.checkNotNull(inputInfo);
+ try {
+ mService.setTvInputInfo(inputInfo, mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Error trying to set " + inputInfo, e);
+ }
+ }
+
+ /**
* Returns the state of a given TV input.
*
* <p>The state is one of the following:
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index f74ae66..a2b6346 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -262,16 +262,16 @@
* <p>The system service automatically creates the TvInputInfo for each TV input based on
* information collected from the AndroidManifest.xml, thus it is not necessary to call this
* method unless the TV input has additional information to pass such as ability to record and
- * tuner count.
+ * tuner count. Attempting to change information about a TV input that the calling package does
+ * not own does nothing.
*
- * @param inputId The ID of the TV input.
+ * @param context The application context.
* @param inputInfo The TvInputInfo object that contains that new information.
*/
- public final void setTvInputInfo(String inputId, TvInputInfo inputInfo) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = inputId;
- args.arg2 = inputInfo;
- mServiceHandler.obtainMessage(ServiceHandler.DO_SET_TV_INPUT_INFO, args).sendToTarget();
+ public static final void setTvInputInfo(Context context, TvInputInfo inputInfo) {
+ TvInputManager manager = (TvInputManager) context.getSystemService(
+ Context.TV_INPUT_SERVICE);
+ manager.setTvInputInfo(inputInfo);
}
private boolean isPassthroughInput(String inputId) {
@@ -1938,7 +1938,6 @@
private static final int DO_REMOVE_HARDWARE_TV_INPUT = 5;
private static final int DO_ADD_HDMI_TV_INPUT = 6;
private static final int DO_REMOVE_HDMI_TV_INPUT = 7;
- private static final int DO_SET_TV_INPUT_INFO = 8;
private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
@@ -1976,18 +1975,6 @@
mCallbacks.finishBroadcast();
}
- private void broadcastSetTvInputInfo(String inputId, TvInputInfo inputInfo) {
- int n = mCallbacks.beginBroadcast();
- for (int i = 0; i < n; ++i) {
- try {
- mCallbacks.getBroadcastItem(i).setTvInputInfo(inputId, inputInfo);
- } catch (RemoteException e) {
- Log.e(TAG, "error in broadcastSetTvInputInfo", e);
- }
- }
- mCallbacks.finishBroadcast();
- }
-
@Override
public final void handleMessage(Message msg) {
switch (msg.what) {
@@ -2120,16 +2107,6 @@
}
return;
}
- case DO_SET_TV_INPUT_INFO: {
- SomeArgs args = (SomeArgs) msg.obj;
- String inputId = (String) args.arg1;
- TvInputInfo inputInfo = (TvInputInfo) args.arg2;
- if (inputInfo != null) {
- broadcastSetTvInputInfo(inputId, inputInfo);
- }
- args.recycle();
- return;
- }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
return;
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
new file mode 100644
index 0000000..5a6553f
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard_shortcuts_keyword_wrapper"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:paddingBottom="8dp">
+ <TextView
+ android:id="@+id/keyboard_shortcuts_keyword"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="12dp"
+ android:background="@android:color/white"
+ android:textColor="#D9000000"
+ android:textSize="16sp"
+ android:maxLines="5"
+ android:singleLine="false"
+ android:scrollHorizontally="false"
+ android:layout_alignParentStart="true"
+ android:minWidth="100dp"
+ android:maxWidth="260dp"/>
+ <!--TODO: introduce and use a layout that allows wrapping and right align -->
+ <LinearLayout
+ android:id="@+id/keyboard_shortcuts_item_container"
+ android:layout_toEndOf="@+id/keyboard_shortcuts_keyword"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/white"
+ android:layout_alignParentEnd="true"
+ android:gravity="end"
+ android:textSize="14sp"
+ android:paddingStart="0dp"
+ android:paddingEnd="0dp"
+ android:scrollHorizontally="false"
+ android:minWidth="100dp"
+ android:maxWidth="260dp"/>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
new file mode 100644
index 0000000..80a478a
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textSize="14sp"
+ android:paddingStart="24dp"
+ android:paddingTop="20dp"
+ android:paddingEnd="24dp"
+ android:paddingBottom="13dp" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
new file mode 100644
index 0000000..fa07eb1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
new file mode 100644
index 0000000..5002c12
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:padding="4dp"
+ android:background="#EEEEEE"
+ android:textColor="#8C000000"
+ android:singleLine="true"
+ android:textSize="14sp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index 460433e..77b1264 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
+ ~ Copyright (C) 2016 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.
@@ -14,11 +14,25 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/keyboard_shortcuts_wrapper"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="40dp"
- android:focusable="true">
-</RelativeLayout>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard_shortcuts_wrapper"
+ android:layout_width="488dp"
+ android:layout_height="wrap_content"
+ android:focusable="true">
+ <ScrollView
+ android:id="@+id/keyboard_shortcuts_scroll_view"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <LinearLayout
+ android:id="@+id/keyboard_shortcuts_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+ </ScrollView>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
new file mode 100644
index 0000000..802acfe
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f0d9949..9bb6dc6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -154,4 +154,9 @@
<color name="switch_bar_background">#ff37474f</color>
<color name="switch_accent_color">#ff7fcac3</color>
+
+ <!-- Keyboard shortcuts colors -->
+ <color name="ksh_system_group_color">#ff00bcd4</color>
+ <color name="ksh_application_group_color">#fff44336</color>
+ <color name="ksh_dialog_background_color">#ffffffff</color>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 240d32e..4edb976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1175,7 +1175,7 @@
}
protected void toggleKeyboardShortcuts() {
- getKeyboardShortcuts().toggleKeyboardShortcuts(mContext);
+ getKeyboardShortcuts().toggleKeyboardShortcuts();
}
protected void cancelPreloadingRecents() {
@@ -1518,7 +1518,7 @@
protected KeyboardShortcuts getKeyboardShortcuts() {
if (mKeyboardShortcuts == null) {
- mKeyboardShortcuts = new KeyboardShortcuts();
+ mKeyboardShortcuts = new KeyboardShortcuts(mContext);
}
return mKeyboardShortcuts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index b36fb7e..25e9a7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -19,25 +19,38 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.graphics.Color;
+import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.Window;
-import android.view.WindowManager;
import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
+import java.util.ArrayList;
import java.util.List;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
-import static android.graphics.Color.TRANSPARENT;
+import static android.graphics.Color.WHITE;
import static android.view.Gravity.TOP;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -45,33 +58,44 @@
* Contains functionality for handling keyboard shortcuts.
*/
public class KeyboardShortcuts {
- private static final String TAG = "KeyboardShortcuts";
+ private static final char SYSTEM_HOME_BASE_CHARACTER = '\u2386';
+ private static final char SYSTEM_BACK_BASE_CHARACTER = '\u007F';
+ private static final char SYSTEM_RECENTS_BASE_CHARACTER = '\u0009';
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Context mContext;
+ private final OnClickListener dialogCloseListener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dismissKeyboardShortcutsDialog();
+ }
+ };
private Dialog mKeyboardShortcutsDialog;
- public KeyboardShortcuts() {}
+ public KeyboardShortcuts(Context context) {
+ this.mContext = context;
+ }
- public void toggleKeyboardShortcuts(final Context context) {
+ public void toggleKeyboardShortcuts() {
if (mKeyboardShortcutsDialog == null) {
- Recents.getSystemServices().requestKeyboardShortcuts(context,
+ Recents.getSystemServices().requestKeyboardShortcuts(mContext,
new KeyboardShortcutsReceiver() {
@Override
public void onKeyboardShortcutsReceived(
final List<KeyboardShortcutGroup> result) {
KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
- context.getString(R.string.keyboard_shortcut_group_system));
+ mContext.getString(R.string.keyboard_shortcut_group_system), true);
systemGroup.addItem(new KeyboardShortcutInfo(
- context.getString(R.string.keyboard_shortcut_group_system_home),
- '\u2386', KeyEvent.META_META_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_home),
+ SYSTEM_HOME_BASE_CHARACTER, KeyEvent.META_META_ON));
systemGroup.addItem(new KeyboardShortcutInfo(
- context.getString(R.string.keyboard_shortcut_group_system_back),
- '\u007F', KeyEvent.META_META_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_back),
+ SYSTEM_BACK_BASE_CHARACTER, KeyEvent.META_META_ON));
systemGroup.addItem(new KeyboardShortcutInfo(
- context.getString(R.string.keyboard_shortcut_group_system_recents),
- '\u0009', KeyEvent.META_ALT_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_recents),
+ SYSTEM_RECENTS_BASE_CHARACTER, KeyEvent.META_ALT_ON));
result.add(systemGroup);
- Log.i(TAG, "Keyboard shortcuts received: " + String.valueOf(result));
- showKeyboardShortcutsDialog(context);
+ showKeyboardShortcutsDialog(result);
}
});
} else {
@@ -79,33 +103,6 @@
}
}
- private void showKeyboardShortcutsDialog(Context context) {
- // Create dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- LAYOUT_INFLATER_SERVICE);
- final View keyboardShortcutsView = inflater.inflate(
- R.layout.keyboard_shortcuts_view, null);
-
- populateKeyboardShortcuts(keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_wrapper));
- dialogBuilder.setView(keyboardShortcutsView);
- mKeyboardShortcutsDialog = dialogBuilder.create();
- mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
-
- // Setup window.
- Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
- keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
- keyboardShortcutsWindow.setBackgroundDrawable(
- new ColorDrawable(TRANSPARENT));
- keyboardShortcutsWindow.setGravity(TOP);
- keyboardShortcutsView.post(new Runnable() {
- public void run() {
- mKeyboardShortcutsDialog.show();
- }
- });
- }
-
public void dismissKeyboardShortcutsDialog() {
if (mKeyboardShortcutsDialog != null) {
mKeyboardShortcutsDialog.dismiss();
@@ -113,11 +110,99 @@
}
}
- /**
- * @return {@code true} if the keyboard shortcuts have been successfully populated.
- */
- private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) {
- // TODO: Populate shortcuts.
- return true;
+ private void showKeyboardShortcutsDialog(
+ final List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ // Need to post on the main thread.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // TODO: break all this code out into a handleShowKeyboard...
+ // Might add more things posted; should consider adding a custom handler so
+ // you can send the keyboardShortcutsGroups as part of the message.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ LAYOUT_INFLATER_SERVICE);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_view, null);
+ DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+ ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_scroll_view);
+ // TODO: find a better way to set the height.
+ scrollView.setLayoutParams(new LinearLayout.LayoutParams(
+ LayoutParams.WRAP_CONTENT,
+ (int) (dm.heightPixels * dm.density)));
+
+ populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
+ dialogBuilder.setView(keyboardShortcutsView);
+ dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
+ mKeyboardShortcutsDialog = dialogBuilder.create();
+ mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+
+ // Setup window.
+ Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ keyboardShortcutsWindow.setBackgroundDrawable(
+ mContext.getDrawable(R.color.ksh_dialog_background_color));
+ keyboardShortcutsWindow.setGravity(TOP);
+ mKeyboardShortcutsDialog.show();
+ }
+ });
+ }
+
+ private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout,
+ List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ final int keyboardShortcutGroupsSize = keyboardShortcutGroups.size();
+ for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+ KeyboardShortcutGroup group = keyboardShortcutGroups.get(i);
+ TextView categoryTitle = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+ categoryTitle.setText(group.getLabel());
+ categoryTitle.setTextColor(group.isSystemGroup()
+ ? mContext.getColor(R.color.ksh_system_group_color)
+ : mContext.getColor(R.color.ksh_application_group_color));
+ keyboardShortcutsLayout.addView(categoryTitle);
+
+ LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_wrapper, null);
+ final int itemsSize = group.getItems().size();
+ for (int j = 0; j < itemsSize; j++) {
+ KeyboardShortcutInfo info = group.getItems().get(j);
+ View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null);
+ TextView textView = (TextView) shortcutView
+ .findViewById(R.id.keyboard_shortcuts_keyword);
+ textView.setText(info.getLabel());
+
+ List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
+ final int shortcutKeysSize = shortcutKeys.size();
+ for (int k = 0; k < shortcutKeysSize; k++) {
+ String shortcutKey = shortcutKeys.get(k);
+ TextView shortcutKeyView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_view, null);
+ shortcutKeyView.setText(shortcutKey);
+ LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+ .findViewById(R.id.keyboard_shortcuts_item_container);
+ shortcutItemsContainer.addView(shortcutKeyView);
+ }
+ shortcutWrapper.addView(shortcutView);
+ }
+
+ // TODO: merge container and wrapper into one xml file - wrapper is always a child of
+ // container.
+ LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_container, null);
+ shortcutsContainer.addView(shortcutWrapper);
+ keyboardShortcutsLayout.addView(shortcutsContainer);
+ }
+ }
+
+ private List<String> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+ // TODO: fix the shortcuts. Find or build an util which can produce human readable
+ // names of the baseCharacter and the modifiers.
+ List<String> shortcutKeys = new ArrayList<>();
+ shortcutKeys.add(KeyEvent.metaStateToString(info.getModifiers()).toUpperCase());
+ shortcutKeys.add(Character.getName(info.getBaseCharacter()).toUpperCase());
+ return shortcutKeys;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 03809c0..2a8672d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -27,6 +27,7 @@
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -51,6 +52,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -258,10 +260,9 @@
UserState userState = getCurrentUserStateLocked();
// We have to reload the installed services since some services may
// have different attributes, resolve info (does not support equals),
- // etc. Remove them then to force reload. Do it even if automation is
- // running since when it goes away, we will have to reload as well.
+ // etc. Remove them then to force reload.
userState.mInstalledServices.clear();
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
if (readConfigurationForUserStateLocked(userState)) {
onUserStateChangedLocked(userState);
}
@@ -296,7 +297,7 @@
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
userState.mTouchExplorationGrantedServices, userId);
// We will update when the automation service dies.
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
onUserStateChangedLocked(userState);
}
return;
@@ -330,7 +331,7 @@
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
userState.mEnabledServices, userId);
// We will update when the automation service dies.
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
onUserStateChangedLocked(userState);
}
}
@@ -362,7 +363,7 @@
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
// We will update when the automation service dies.
UserState userState = getCurrentUserStateLocked();
- if (userState.mUiAutomationService == null) {
+ if (!userState.isUiAutomationSuppressingOtherServices()) {
if (readConfigurationForUserStateLocked(userState)) {
onUserStateChangedLocked(userState);
}
@@ -473,11 +474,9 @@
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
- // The automation service is a fake one and should not be reported
- // to clients as being enabled. The automation service is always the
- // only active one, if it exists.
+ // The automation service can suppress other services.
UserState userState = getUserStateLocked(resolvedUserId);
- if (userState.mUiAutomationService != null) {
+ if (userState.isUiAutomationSuppressingOtherServices()) {
return Collections.emptyList();
}
@@ -490,7 +489,9 @@
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
Service service = services.get(i);
- if ((service.mFeedbackType & feedbackTypeBit) != 0) {
+ // Don't report the UIAutomation (fake service)
+ if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)
+ && (service.mFeedbackType & feedbackTypeBit) != 0) {
result.add(service.mAccessibilityServiceInfo);
}
}
@@ -621,7 +622,8 @@
@Override
public void registerUiTestAutomationService(IBinder owner,
IAccessibilityServiceClient serviceClient,
- AccessibilityServiceInfo accessibilityServiceInfo) {
+ AccessibilityServiceInfo accessibilityServiceInfo,
+ int flags) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
@@ -645,15 +647,17 @@
userState.mUiAutomationServiceOwner = owner;
userState.mUiAutomationServiceClient = serviceClient;
-
- // Set the temporary state.
+ userState.mUiAutomationFlags = flags;
userState.mIsAccessibilityEnabled = true;
- userState.mIsTouchExplorationEnabled = false;
- userState.mIsEnhancedWebAccessibilityEnabled = false;
- userState.mIsDisplayMagnificationEnabled = false;
- userState.mIsAutoclickEnabled = false;
userState.mInstalledServices.add(accessibilityServiceInfo);
- userState.mEnabledServices.clear();
+ if (userState.isUiAutomationSuppressingOtherServices()) {
+ // Set the temporary state.
+ userState.mIsTouchExplorationEnabled = false;
+ userState.mIsEnhancedWebAccessibilityEnabled = false;
+ userState.mIsDisplayMagnificationEnabled = false;
+ userState.mIsAutoclickEnabled = false;
+ userState.mEnabledServices.clear();
+ }
userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
@@ -694,7 +698,7 @@
UserState userState = getCurrentUserStateLocked();
// This is a nop if UI automation is enabled.
- if (userState.mUiAutomationService != null) {
+ if (userState.isUiAutomationSuppressingOtherServices()) {
return;
}
@@ -1027,6 +1031,9 @@
if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
userState.mEnabledServices.clear();
userState.mEnabledServices.addAll(mTempComponentNameSet);
+ if (userState.mUiAutomationService != null) {
+ userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
+ }
mTempComponentNameSet.clear();
return true;
}
@@ -3981,6 +3988,7 @@
public boolean mAccessibilityFocusOnlyInActiveWindow;
private Service mUiAutomationService;
+ private int mUiAutomationFlags;
private IAccessibilityServiceClient mUiAutomationServiceClient;
private IBinder mUiAutomationServiceOwner;
@@ -4044,6 +4052,7 @@
public void destroyUiAutomationService() {
mUiAutomationService = null;
+ mUiAutomationFlags = 0;
mUiAutomationServiceClient = null;
if (mUiAutomationServiceOwner != null) {
mUiAutomationServiceOwner.unlinkToDeath(
@@ -4051,6 +4060,11 @@
mUiAutomationServiceOwner = null;
}
}
+
+ boolean isUiAutomationSuppressingOtherServices() {
+ return ((mUiAutomationService != null) && (mUiAutomationFlags
+ & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0);
+ }
}
private final class AccessibilityContentObserver extends ContentObserver {
@@ -4130,8 +4144,8 @@
// we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
- // We will update when the automation service dies.
- if (userState.mUiAutomationService != null) {
+ // If the automation service is suppressing, we will update when it dies.
+ if (userState.isUiAutomationSuppressingOtherServices()) {
return;
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index e9f0a7a..d0cd536 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -200,7 +200,7 @@
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+ .setSmallIcon(com.android.internal.R.drawable.ic_secure)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 573afd6..033a243 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,7 +16,9 @@
package com.android.server.input;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.LocaleList;
import android.view.Display;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.os.SomeArgs;
@@ -780,8 +782,10 @@
|| layout.getProductId() != d.getProductId()) {
return;
}
- for (Locale l : layout.getLocales()) {
- if (isCompatibleLocale(systemLocale, l)) {
+ final LocaleList locales = layout.getLocales();
+ final int numLocales = locales.size();
+ for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+ if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
layouts.add(layout);
break;
}
@@ -799,9 +803,12 @@
final int N = layouts.size();
for (int i = 0; i < N; i++) {
KeyboardLayout layout = layouts.get(i);
- for (Locale l : layout.getLocales()) {
- if (l.getCountry().equals(systemLocale.getCountry())
- && l.getVariant().equals(systemLocale.getVariant())) {
+ final LocaleList locales = layout.getLocales();
+ final int numLocales = locales.size();
+ for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+ final Locale locale = locales.get(localeIndex);
+ if (locale.getCountry().equals(systemLocale.getCountry())
+ && locale.getVariant().equals(systemLocale.getVariant())) {
return layout.getDescriptor();
}
}
@@ -809,8 +816,11 @@
// Then try an exact match of language and country
for (int i = 0; i < N; i++) {
KeyboardLayout layout = layouts.get(i);
- for (Locale l : layout.getLocales()) {
- if (l.getCountry().equals(systemLocale.getCountry())) {
+ final LocaleList locales = layout.getLocales();
+ final int numLocales = locales.size();
+ for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+ final Locale locale = locales.get(localeIndex);
+ if (locale.getCountry().equals(systemLocale.getCountry())) {
return layout.getDescriptor();
}
}
@@ -1170,7 +1180,7 @@
0);
String languageTags = a.getString(
com.android.internal.R.styleable.KeyboardLayout_locale);
- Locale[] locales = getLocalesFromLanguageTags(languageTags);
+ LocaleList locales = getLocalesFromLanguageTags(languageTags);
int vid = a.getInt(
com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
int pid = a.getInt(
@@ -1210,16 +1220,12 @@
}
}
- private static Locale[] getLocalesFromLanguageTags(String languageTags) {
+ @NonNull
+ private static LocaleList getLocalesFromLanguageTags(String languageTags) {
if (TextUtils.isEmpty(languageTags)) {
- return new Locale[0];
+ return LocaleList.getEmptyLocaleList();
}
- String[] tags = languageTags.split("\\|");
- Locale[] locales = new Locale[tags.length];
- for (int i = 0; i < tags.length; i++) {
- locales[i] = Locale.forLanguageTag(tags[i]);
- }
- return locales;
+ return LocaleList.forLanguageTags(languageTags.replace('|', ','));
}
/**
@@ -1596,7 +1602,7 @@
final int accessibilityConfig = Settings.Secure.getIntForUser(
mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
0, UserHandle.USER_CURRENT);
- PointerIcon.sUseLargeIcons = (accessibilityConfig == 1);
+ PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
nativeReloadPointerIcons(mPtr);
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 62e7fb4..318f966 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -71,6 +71,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.InputChannel;
@@ -779,15 +780,14 @@
}
}
- private void notifyTvInputInfoChanged(UserState userState, String inputId,
- TvInputInfo inputInfo) {
+ private void setTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
if (DEBUG) {
- Slog.d(TAG, "notifyTvInputInfoChanged(inputId=" + inputId + ", inputInfo=" + inputInfo
- + ")");
+ Slog.d(TAG, "setTvInputInfoLocked(inputInfo=" + inputInfo + ")");
}
+ // TODO: Also update the internal input list.
for (ITvInputManagerCallback callback : userState.callbackSet) {
try {
- callback.onTvInputInfoChanged(inputId, inputInfo);
+ callback.onTvInputInfoChanged(inputInfo);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report changed input info to callback", e);
}
@@ -846,6 +846,36 @@
}
}
+ public void setTvInputInfo(TvInputInfo inputInfo, int userId) {
+ String inputInfoPackageName = inputInfo.getServiceInfo().packageName;
+ String callingPackageName = getCallingPackageName();
+ if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) {
+ throw new IllegalArgumentException("calling package " + callingPackageName
+ + " is not allowed to change TvInputInfo for " + inputInfoPackageName);
+ }
+
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "setTvInputInfoChanged");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ setTvInputInfoLocked(userState, inputInfo);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private String getCallingPackageName() {
+ final String[] packages = mContext.getPackageManager().getPackagesForUid(
+ Binder.getCallingUid());
+ if (packages != null && packages.length > 0) {
+ return packages[0];
+ }
+ return "unknown";
+ }
+
@Override
public int getTvInputState(String inputId, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
@@ -2233,18 +2263,6 @@
}
}
}
-
- @Override
- public void setTvInputInfo(String inputId, TvInputInfo inputInfo) {
- ensureValidInput(inputInfo);
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "setTvInputInfo(" + inputInfo + ")");
- }
- UserState userState = getOrCreateUserStateLocked(mUserId);
- notifyTvInputInfoChanged(userState, inputId, inputInfo);
- }
- }
}
private final class SessionCallback extends ITvInputSessionCallback.Stub {
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 0979cd3..66aa863 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -35,10 +35,10 @@
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG = false;
- static final boolean DEBUG_ADD_REMOVE = false;
+ static final boolean DEBUG_ADD_REMOVE = true;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
- static final boolean DEBUG_ANIM = false;
+ static final boolean DEBUG_ANIM = true;
static final boolean DEBUG_KEYGUARD = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_LAYERS = false;
@@ -50,7 +50,7 @@
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
- static final boolean DEBUG_APP_TRANSITIONS = false;
+ static final boolean DEBUG_APP_TRANSITIONS = true;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1214948..4dd2b4d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -751,15 +751,16 @@
Math.min(mStableFrame.bottom, frame.bottom));
}
- mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
- Math.max(mOverscanFrame.top - frame.top, 0),
- Math.max(frame.right - mOverscanFrame.right, 0),
- Math.max(frame.bottom - mOverscanFrame.bottom, 0));
-
-
+ if (!inFreeformWorkspace()) {
+ // Freeform windows can be positioned outside of the display frame, but that is not a
+ // reason to provide them with overscan insets.
+ mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
+ Math.max(mOverscanFrame.top - frame.top, 0),
+ Math.max(frame.right - mOverscanFrame.right, 0),
+ Math.max(frame.bottom - mOverscanFrame.bottom, 0));
+ }
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
-
// For the docked divider, we calculate the stable insets like a full-screen window
// so it can use it to calculate the snap positions.
mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
@@ -2238,7 +2239,8 @@
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
- pw.print(" isReadyForDisplay()="); pw.println(isReadyForDisplay());
+ pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
+ pw.print(" hasSavedSurface()="); pw.println(hasSavedSurface());
if (dumpAll) {
pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
pw.print(" last="); mLastFrame.printShortString(pw);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index cffcc5d..428ab7a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -567,6 +567,10 @@
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
+ if (w.hasSavedSurface()) {
+ Slog.i(TAG, "***** createSurface: " + this + ": called when we had a saved surface");
+ }
+
if (mSurfaceController == null) {
if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
"createSurface " + this + ": mDrawState=DRAW_PENDING");