Merge "Clear selection after copy and when back is pressed."
diff --git a/Android.mk b/Android.mk
index 5983b30..ad164e20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -187,6 +187,8 @@
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
+ core/java/android/hardware/location/IContextHubCallback.aidl \
+ core/java/android/hardware/location/IContextHubService.aidl \
core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/ICaptivePortal.aidl \
@@ -417,6 +419,7 @@
telephony/java/com/android/internal/telephony/ISub.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
+ telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index aa503af..3260d4c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2625,6 +2625,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2683,6 +2684,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -4642,6 +4655,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 +5552,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 +5569,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
@@ -5821,6 +5837,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -5890,6 +5907,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6301,7 +6319,6 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
- method public int getMetering();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6310,9 +6327,6 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
- field public static final int METERING_ALL = -1; // 0xffffffff
- field public static final int METERING_DEFAULT = 1; // 0x1
- field public static final int METERING_METERED = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_DEFAULT = 1; // 0x1
field public static final int ROAMING_ROAMING = 2; // 0x2
@@ -19871,6 +19885,7 @@
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
method public int getState();
+ method public int getTimestamp(android.media.AudioTimestamp, int);
method public int read(byte[], int, int);
method public int read(byte[], int, int, int);
method public int read(short[], int, int);
@@ -19942,6 +19957,8 @@
public final class AudioTimestamp {
ctor public AudioTimestamp();
+ field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+ field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
field public long framePosition;
field public long nanoTime;
}
@@ -22496,6 +22513,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 +22592,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 +22909,8 @@
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 onInputUpdated(java.lang.String);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22898,7 +22918,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";
}
@@ -22969,7 +22989,7 @@
method public void stopRecording();
}
- public class TvRecordingClient.RecordingCallback {
+ public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
method public void onConnected();
method public void onDisconnected();
@@ -28536,6 +28556,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 +29151,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);
@@ -29592,6 +29617,8 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -32042,6 +32069,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -51298,6 +51326,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 95c19d7..ef6506d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2727,6 +2727,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2785,6 +2786,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -4774,6 +4787,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 +5684,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 +5701,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
@@ -5961,6 +5977,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -6036,6 +6053,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6558,7 +6576,6 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
- method public int getMetering();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6567,9 +6584,6 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
- field public static final int METERING_ALL = -1; // 0xffffffff
- field public static final int METERING_DEFAULT = 1; // 0x1
- field public static final int METERING_METERED = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_DEFAULT = 1; // 0x1
field public static final int ROAMING_ROAMING = 2; // 0x2
@@ -9956,6 +9970,7 @@
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
@@ -15123,6 +15138,66 @@
package android.hardware.location {
+ public class ContextHubInfo {
+ ctor public ContextHubInfo();
+ method public int describeContents();
+ method public int getId();
+ method public android.hardware.location.MemoryRegion[] getMemoryRegions();
+ method public java.lang.String getName();
+ method public float getPeakMips();
+ method public float getPeakPowerDrawMw();
+ method public int getPlatformVersion();
+ method public float getSleepPowerDrawMw();
+ method public int getStaticSwVersion();
+ method public float getStoppedPowerDrawMw();
+ method public int[] getSupportedSensors();
+ method public java.lang.String getToolchain();
+ method public int getToolchainVersion();
+ method public java.lang.String getVendor();
+ method public void setId(int);
+ method public void setMemoryRegions(android.hardware.location.MemoryRegion[]);
+ method public void setName(java.lang.String);
+ method public void setPeakMips(float);
+ method public void setPeakPowerDrawMw(float);
+ method public void setPlatformVersion(int);
+ method public void setSleepPowerDrawMw(float);
+ method public void setStaticSwVersion(int);
+ method public void setStoppedPowerDrawMw(float);
+ method public void setSupportedSensors(int[]);
+ method public void setToolchain(java.lang.String);
+ method public void setToolchainVersion(int);
+ method public void setVendor(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
+ }
+
+ public final class ContextHubManager {
+ method public java.lang.Integer[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+ method public int[] getContexthubHandles();
+ method public android.hardware.location.ContextHubInfo getContexthubInfo(int);
+ method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+ method public int loadNanoApp(int, android.hardware.location.NanoApp);
+ method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
+ method public int unloadNanoApp(int);
+ field public static final int ANY_HUB = -1; // 0xffffffff
+ field public static final int MSG_DATA_SEND = 3; // 0x3
+ field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
+ field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
+ }
+
+ public class ContextHubMessage {
+ ctor public ContextHubMessage(int, int, byte[]);
+ method public int describeContents();
+ method public byte[] getData();
+ method public int getMsgType();
+ method public int getVersion();
+ method public void setMsgData(byte[]);
+ method public void setMsgType(int);
+ method public void setVersion(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
+ }
+
public final class GeofenceHardware {
ctor public GeofenceHardware(android.hardware.location.IGeofenceHardware);
method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
@@ -15239,6 +15314,89 @@
method public abstract void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent) throws android.os.RemoteException;
}
+ public class MemoryRegion implements android.os.Parcelable {
+ ctor public MemoryRegion(android.os.Parcel);
+ method public int describeContents();
+ method public int getCapacityBytes();
+ method public int getFreeCapacityBytes();
+ method public boolean isExecutable();
+ method public boolean isReadable();
+ method public boolean isWritable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
+ }
+
+ public class NanoApp {
+ ctor public NanoApp();
+ method public int describeContents();
+ method public byte[] getAppBinary();
+ method public int getAppId();
+ method public int getAppVersion();
+ method public java.lang.String getName();
+ method public int getNeededExecMemBytes();
+ method public int getNeededReadMemBytes();
+ method public int[] getNeededSensors();
+ method public int getNeededWriteMemBytes();
+ method public int[] getOutputEvents();
+ method public java.lang.String getPublisher();
+ method public void setAppBinary(byte[]);
+ method public void setAppId(int);
+ method public void setAppVersion(int);
+ method public void setName(java.lang.String);
+ method public void setNeededExecMemBytes(int);
+ method public void setNeededReadMemBytes(int);
+ method public void setNeededSensors(int[]);
+ method public void setNeededWriteMemBytes(int);
+ method public void setOutputEvents(int[]);
+ method public void setPublisher(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
+ }
+
+ public class NanoAppFilter {
+ ctor public NanoAppFilter(long, int, int, long);
+ method public int describeContents();
+ method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int APP_ANY = -1; // 0xffffffff
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
+ field public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
+ field public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
+ field public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
+ field public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
+ field public static final int HUB_ANY = -1; // 0xffffffff
+ field public static final int VENDOR_ANY = -1; // 0xffffffff
+ }
+
+ public class NanoAppInstanceInfo {
+ ctor public NanoAppInstanceInfo();
+ method public int describeContents();
+ method public int getAppId();
+ method public int getAppVersion();
+ method public int getContexthubId();
+ method public int getHandle();
+ method public java.lang.String getName();
+ method public int getNeededExecMemBytes();
+ method public int getNeededReadMemBytes();
+ method public int[] getNeededSensors();
+ method public int getNeededWriteMemBytes();
+ method public int[] getOutputEvents();
+ method public java.lang.String getPublisher();
+ method public void setAppId(int);
+ method public void setAppVersion(int);
+ method public void setContexthubId(int);
+ method public void setHandle(int);
+ method public void setName(java.lang.String);
+ method public void setNeededExecMemBytes(int);
+ method public void setNeededReadMemBytes(int);
+ method public void setNeededSensors(int[]);
+ method public void setNeededWriteMemBytes(int);
+ method public void setOutputEvents(int[]);
+ method public void setPublisher(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
+ }
+
}
package android.hardware.radio {
@@ -20993,6 +21151,7 @@
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
method public int getState();
+ method public int getTimestamp(android.media.AudioTimestamp, int);
method public int read(byte[], int, int);
method public int read(byte[], int, int, int);
method public int read(short[], int, int);
@@ -21066,6 +21225,8 @@
public final class AudioTimestamp {
ctor public AudioTimestamp();
+ field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+ field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
field public long framePosition;
field public long nanoTime;
}
@@ -23693,6 +23854,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
}
@@ -23771,6 +23933,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
@@ -24261,7 +24424,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 {
@@ -24273,7 +24436,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";
}
@@ -24353,7 +24516,7 @@
method public void stopRecording();
}
- public class TvRecordingClient.RecordingCallback {
+ public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
method public void onConnected();
method public void onDisconnected();
@@ -30420,6 +30583,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);
@@ -31019,6 +31186,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);
@@ -31062,6 +31230,7 @@
method public deprecated boolean isOwner();
method public boolean isSystem();
method public static int myUserId();
+ method public static android.os.UserHandle of(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -31076,6 +31245,7 @@
method public android.os.PersistableBundle getSeedAccountOptions();
method public java.lang.String getSeedAccountType();
method public long getSerialNumberForUser(android.os.UserHandle);
+ method public long[] getSerialNumbersOfUsers(boolean);
method public int getUserCount();
method public long getUserCreationTime(android.os.UserHandle);
method public android.os.UserHandle getUserForSerialNumber(long);
@@ -31493,6 +31663,9 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageCredentialEncrypted();
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -34075,6 +34248,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -53905,6 +54079,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 081c471..db1ca19 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2625,6 +2625,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2683,6 +2684,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -4642,6 +4655,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 +5552,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 +5571,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
@@ -5823,6 +5839,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -5892,6 +5909,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6303,7 +6321,6 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
- method public int getMetering();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6312,9 +6329,6 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
- field public static final int METERING_ALL = -1; // 0xffffffff
- field public static final int METERING_DEFAULT = 1; // 0x1
- field public static final int METERING_METERED = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_DEFAULT = 1; // 0x1
field public static final int ROAMING_ROAMING = 2; // 0x2
@@ -19880,6 +19894,7 @@
method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSampleRate();
method public int getState();
+ method public int getTimestamp(android.media.AudioTimestamp, int);
method public int read(byte[], int, int);
method public int read(byte[], int, int, int);
method public int read(short[], int, int);
@@ -19951,6 +19966,8 @@
public final class AudioTimestamp {
ctor public AudioTimestamp();
+ field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+ field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
field public long framePosition;
field public long nanoTime;
}
@@ -22505,6 +22522,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 +22601,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 +22918,8 @@
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 onInputUpdated(java.lang.String);
+ method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22907,7 +22927,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";
}
@@ -22978,7 +22998,7 @@
method public void stopRecording();
}
- public class TvRecordingClient.RecordingCallback {
+ public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
method public void onConnected();
method public void onDisconnected();
@@ -28545,6 +28565,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 +29160,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);
@@ -29602,6 +29627,8 @@
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
+ method public void setStorageDefault();
+ method public void setStorageDeviceEncrypted();
field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
}
@@ -32055,6 +32082,7 @@
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+ field public static final java.lang.String ACTION_KEYBOARD_LAYOUT_SETTINGS = "android.settings.KEYBOARD_LAYOUT_SETTINGS";
field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
@@ -51315,6 +51343,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8bc17f8..c96cca2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,6 +17,7 @@
package android.accessibilityservice;
import android.accessibilityservice.GestureDescription.MotionEventGenerator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
@@ -29,6 +30,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -46,10 +48,13 @@
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
- * An accessibility service runs in the background and receives callbacks by the system
+ * Accessibility services are intended to assist users with disabilities in using
+ * Android devices and apps. They run in the background and receive callbacks by the system
* when {@link AccessibilityEvent}s are fired. Such events denote some state transition
* in the user interface, for example, the focus has changed, a button has been clicked,
* etc. Such a service can optionally request the capability for querying the content
@@ -66,22 +71,31 @@
* <h3>Lifecycle</h3>
* <p>
* The lifecycle of an accessibility service is managed exclusively by the system and
- * follows the established service life cycle. Additionally, starting or stopping an
- * accessibility service is triggered exclusively by an explicit user action through
- * enabling or disabling it in the device settings. After the system binds to a service it
- * calls {@link AccessibilityService#onServiceConnected()}. This method can be
- * overriden by clients that want to perform post binding setup.
+ * follows the established service life cycle. Starting an accessibility service is triggered
+ * exclusively by the user explicitly turning the service on in device settings. After the system
+ * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
+ * be overriden by clients that want to perform post binding setup.
+ * </p>
+ * <p>
+ * An accessibility service stops either when the user turns it off in device settings or when
+ * it calls {@link AccessibilityService#disableSelf()}.
* </p>
* <h3>Declaration</h3>
* <p>
- * An accessibility is declared as any other service in an AndroidManifest.xml but it
- * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
- * {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Additionally an accessibility service must request the
- * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
- * that only the system
- * can bind to it. Failure to declare this intent will cause the system to ignore the
- * accessibility service. Following is an example declaration:
+ * An accessibility is declared as any other service in an AndroidManifest.xml, but it
+ * must do two things:
+ * <ul>
+ * <ol>
+ * Specify that it handles the "android.accessibilityservice.AccessibilityService"
+ * {@link android.content.Intent}.
+ * </ol>
+ * <ol>
+ * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
+ * ensure that only the system can bind to it.
+ * </ol>
+ * </ul>
+ * If either of these items is missing, the system will ignore the accessibility service.
+ * Following is an example declaration:
* </p>
* <pre> <service android:name=".MyAccessibilityService"
* android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
@@ -135,48 +149,24 @@
* </ul>
* <h3>Retrieving window content</h3>
* <p>
- * A service can specify in its declaration that it can retrieve the active window
- * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
+ * A service can specify in its declaration that it can retrieve window
+ * content which is represented as a tree of {@link AccessibilityWindowInfo} and
+ * {@link AccessibilityNodeInfo} objects. Note that
* declaring this capability requires that the service declares its configuration via
* an XML resource referenced by {@link #SERVICE_META_DATA}.
* </p>
* <p>
- * For security purposes an accessibility service can retrieve only the content of the
- * currently active window. The currently active window is defined as the window from
- * which was fired the last event of the following types:
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * In other words, the last window that was shown or the last window that the user has touched
- * during touch exploration.
- * </p>
- * <p>
- * The entry point for retrieving window content is through calling
- * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
- * event of the above types or a previous event from the same window
- * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
- * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
- * window content which represented as a tree of such objects.
+ * Window content may be retrieved with
+ * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
+ * {@link AccessibilityService#findFocus(int)},
+ * {@link AccessibilityService#getWindows()}, or
+ * {@link AccessibilityService#getRootInActiveWindow()}.
* </p>
* <p class="note">
* <strong>Note</strong> An accessibility service may have requested to be notified for
- * a subset of the event types, thus be unaware that the active window has changed. Therefore
- * accessibility service that would like to retrieve window content should:
- * <ul>
- * <li>
- * Register for all event types with no notification timeout and keep track for the active
- * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
- * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
- * methods on the latter.
- * </li>
- * <li>
- * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
- * active window has changed and the service did not get the accessibility event yet. Note
- * that it is possible to have a retrieval method failing even adopting the strategy
- * specified in the previous bullet because the accessibility event dispatch is asynchronous
- * and crosses process boundaries.
- * </li>
- * </ul>
+ * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
+ * possible for a node to contain outdated information because the window content may change at any
+ * time.
* </p>
* <h3>Notification strategy</h3>
* <p>
@@ -328,7 +318,6 @@
* android:settingsActivity="foo.bar.TestBackActivity"
* android:canRetrieveWindowContent="true"
* android:canRequestTouchExplorationMode="true"
- * android:canRequestEnhancedWebAccessibility="true"
* . . .
* /></pre>
*/
@@ -378,9 +367,26 @@
public boolean onKeyEvent(KeyEvent event);
public void onMagnificationChanged(@NonNull Region region,
float scale, float centerX, float centerY);
+ public void onSoftKeyboardShowModeChanged(int showMode);
public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
+ /**
+ * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
+ public @interface SoftKeyboardShowMode {};
+ /**
+ * @hide
+ */
+ public static final int SHOW_MODE_AUTO = 0;
+ /**
+ * @hide
+ */
+ public static final int SHOW_MODE_HIDDEN = 1;
+
private int mConnectionId;
private AccessibilityServiceInfo mInfo;
@@ -390,6 +396,7 @@
private WindowManager mWindowManager;
private MagnificationController mMagnificationController;
+ private SoftKeyboardController mSoftKeyboardController;
private int mGestureStatusCallbackSequence;
@@ -528,6 +535,14 @@
* is currently touching or the window with input focus, if the user is not
* touching any window.
* <p>
+ * The currently active window is defined as the window that most recently fired one
+ * of the following events:
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
+ * In other words, the last window shown that also has input focus.
+ * </p>
+ * <p>
* <strong>Note:</strong> In order to access the root node your service has
* to declare the capability to retrieve window content by setting the
* {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
@@ -541,8 +556,8 @@
}
/**
- * This method allows accessibility service turn itself off
- * and the service will become disabled from the Settings.
+ * Disables the service. After calling this method, the service will be disabled and settings
+ * will show that it is turned off.
*/
public final void disableSelf() {
final IAccessibilityServiceConnection connection =
@@ -570,10 +585,12 @@
*/
@NonNull
public final MagnificationController getMagnificationController() {
- if (mMagnificationController == null) {
- mMagnificationController = new MagnificationController(this);
+ synchronized (mLock) {
+ if (mMagnificationController == null) {
+ mMagnificationController = new MagnificationController(this, mLock);
+ }
+ return mMagnificationController;
}
- return mMagnificationController;
}
/**
@@ -677,17 +694,21 @@
* first magnification listener.
*/
private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
+ private final Object mLock;
- MagnificationController(@NonNull AccessibilityService service) {
+ MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
mService = service;
+ mLock = lock;
}
/**
* Called when the service is connected.
*/
void onServiceConnected() {
- if (mListeners != null && !mListeners.isEmpty()) {
- setMagnificationCallbackEnabled(true);
+ synchronized (mLock) {
+ if (mListeners != null && !mListeners.isEmpty()) {
+ setMagnificationCallbackEnabled(true);
+ }
}
}
@@ -714,17 +735,19 @@
*/
public void addListener(@NonNull OnMagnificationChangedListener listener,
@Nullable Handler handler) {
- if (mListeners == null) {
- mListeners = new ArrayMap<>();
- }
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
- final boolean shouldEnableCallback = mListeners.isEmpty();
- mListeners.put(listener, handler);
+ final boolean shouldEnableCallback = mListeners.isEmpty();
+ mListeners.put(listener, handler);
- if (shouldEnableCallback) {
- // This may fail if the service is not connected yet, but if we
- // still have listeners when it connects then we can try again.
- setMagnificationCallbackEnabled(true);
+ if (shouldEnableCallback) {
+ // This may fail if the service is not connected yet, but if we
+ // still have listeners when it connects then we can try again.
+ setMagnificationCallbackEnabled(true);
+ }
}
}
@@ -741,19 +764,21 @@
return false;
}
- final int keyIndex = mListeners.indexOfKey(listener);
- final boolean hasKey = keyIndex >= 0;
- if (hasKey) {
- mListeners.removeAt(keyIndex);
- }
+ synchronized (mLock) {
+ final int keyIndex = mListeners.indexOfKey(listener);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mListeners.removeAt(keyIndex);
+ }
- if (hasKey && mListeners.isEmpty()) {
- // We just removed the last listener, so we don't need
- // callbacks from the service anymore.
- setMagnificationCallbackEnabled(false);
- }
+ if (hasKey && mListeners.isEmpty()) {
+ // We just removed the last listener, so we don't need
+ // callbacks from the service anymore.
+ setMagnificationCallbackEnabled(false);
+ }
- return hasKey;
+ return hasKey;
+ }
}
private void setMagnificationCallbackEnabled(boolean enabled) {
@@ -775,17 +800,19 @@
*/
void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
final float centerX, final float centerY) {
- if (mListeners == null || mListeners.isEmpty()) {
- Slog.d(LOG_TAG, "Received magnification changed "
- + "callback with no listeners registered!");
- setMagnificationCallbackEnabled(false);
- return;
- }
+ final ArrayMap<OnMagnificationChangedListener, Handler> entries;
+ synchronized (mLock) {
+ if (mListeners == null || mListeners.isEmpty()) {
+ Slog.d(LOG_TAG, "Received magnification changed "
+ + "callback with no listeners registered!");
+ setMagnificationCallbackEnabled(false);
+ return;
+ }
- // Listeners may remove themselves. Perform a shallow copy to avoid
- // concurrent modification.
- final ArrayMap<OnMagnificationChangedListener, Handler> entries =
- new ArrayMap<>(mListeners);
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
for (int i = 0, count = entries.size(); i < count; i++) {
final OnMagnificationChangedListener listener = entries.keyAt(i);
@@ -1018,6 +1045,243 @@
}
/**
+ * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
+ * show mode.
+ *
+ * @return the soft keyboard controller
+ */
+ @NonNull
+ public final SoftKeyboardController getSoftKeyboardController() {
+ synchronized (mLock) {
+ if (mSoftKeyboardController == null) {
+ mSoftKeyboardController = new SoftKeyboardController(this, mLock);
+ }
+ return mSoftKeyboardController;
+ }
+ }
+
+ private void onSoftKeyboardShowModeChanged(int showMode) {
+ if (mSoftKeyboardController != null) {
+ mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
+ }
+ }
+
+ /**
+ * Used to control and query the soft keyboard show mode.
+ */
+ public static final class SoftKeyboardController {
+ private final AccessibilityService mService;
+
+ /**
+ * Map of listeners to their handlers. Lazily created when adding the first
+ * soft keyboard change listener.
+ */
+ private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
+ private final Object mLock;
+
+ SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
+ mService = service;
+ mLock = lock;
+ }
+
+ /**
+ * Called when the service is connected.
+ */
+ void onServiceConnected() {
+ synchronized(mLock) {
+ if (mListeners != null && !mListeners.isEmpty()) {
+ setSoftKeyboardCallbackEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * Adds the specified change listener to the list of show mode change listeners. The
+ * callback will occur on the service's main thread. Listener is not called on registration.
+ */
+ public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+ addOnShowModeChangedListener(listener, null);
+ }
+
+ /**
+ * Adds the specified change listener to the list of soft keyboard show mode change
+ * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
+ * services's main thread if the handler is {@code null}.
+ *
+ * @param listener the listener to add, must be non-null
+ * @param handler the handler on which to callback should execute, or {@code null} to
+ * execute on the service's main thread
+ */
+ public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
+ @Nullable Handler handler) {
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
+
+ final boolean shouldEnableCallback = mListeners.isEmpty();
+ mListeners.put(listener, handler);
+
+ if (shouldEnableCallback) {
+ // This may fail if the service is not connected yet, but if we still have
+ // listeners when it connects, we can try again.
+ setSoftKeyboardCallbackEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * Removes all instances of the specified change listener from teh list of magnification
+ * change listeners.
+ *
+ * @param listener the listener to remove, must be non-null
+ * @return {@code true} if at least one instance of the listener was removed
+ */
+ public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+ if (mListeners == null) {
+ return false;
+ }
+
+ synchronized (mLock) {
+ final int keyIndex = mListeners.indexOfKey(listener);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mListeners.removeAt(keyIndex);
+ }
+
+ if (hasKey && mListeners.isEmpty()) {
+ // We just removed the last listener, so we don't need callbacks from the
+ // service anymore.
+ setSoftKeyboardCallbackEnabled(false);
+ }
+
+ return hasKey;
+ }
+ }
+
+ private void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(
+ mService.mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setSoftKeyboardCallbackEnabled(enabled);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * Dispatches the soft keyboard show mode change to any registered listeners. This should
+ * be called on the service's main thread.
+ */
+ void dispatchSoftKeyboardShowModeChanged(final int showMode) {
+ final ArrayMap<OnShowModeChangedListener, Handler> entries;
+ synchronized (mLock) {
+ if (mListeners == null || mListeners.isEmpty()) {
+ Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
+ + " with no listeners registered!");
+ setSoftKeyboardCallbackEnabled(false);
+ return;
+ }
+
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
+
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final OnShowModeChangedListener listener = entries.keyAt(i);
+ final Handler handler = entries.valueAt(i);
+ if (handler != null) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onShowModeChanged(SoftKeyboardController.this, showMode);
+ }
+ });
+ } else {
+ // We're already on the main thread, just run the listener.
+ listener.onShowModeChanged(this, showMode);
+ }
+ }
+ }
+
+ /**
+ * Returns the show mode of the soft keyboard. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+ *
+ * @return the current soft keyboard show mode
+ *
+ * @see Settings#Secure#SHOW_MODE_AUTO
+ * @see Settings#Secure#SHOW_MODE_HIDDEN
+ */
+ @SoftKeyboardShowMode
+ public int getShowMode() {
+ try {
+ return Settings.Secure.getInt(mService.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+ } catch (Settings.SettingNotFoundException e) {
+ Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
+ // The settings hasn't been changed yet, so it's value is null. Return the default.
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the soft keyboard show mode. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
+ * The lastto this method will be honored, regardless of any previous calls (including those
+ * made by other AccessibilityServices).
+ * <p>
+ * <strong>Note:</strong> If the service is not yet conected (e.g.
+ * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
+ * service has been disconnected, this method will hav no effect and return {@code false}.
+ *
+ * @param showMode the new show mode for the soft keyboard
+ * @return {@code true} on success
+ *
+ * @see Settings#Secure#SHOW_MODE_AUTO
+ * @see Settings#Secure#SHOW_MODE_HIDDEN
+ */
+ public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(
+ mService.mConnectionId);
+ if (connection != null) {
+ try {
+ return connection.setSoftKeyboardShowMode(showMode);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Falied to set soft keyboard behavior", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Listener for changes in the soft keyboard show mode.
+ */
+ public interface OnShowModeChangedListener {
+ /**
+ * Called when the soft keyboard behavior changes. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+ *
+ * @param controller the soft keyboard controller
+ * @param showMode the current soft keyboard show mode
+ */
+ void onShowModeChanged(@NonNull SoftKeyboardController controller,
+ @SoftKeyboardShowMode int showMode);
+ }
+ }
+
+ /**
* 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
@@ -1054,7 +1318,7 @@
* property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
* Also the service has to opt-in to retrieve the interactive windows by
* setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
- * flag.Otherwise, the search will be performed only in the active window.
+ * flag. Otherwise, the search will be performed only in the active window.
* </p>
*
* @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
@@ -1191,6 +1455,11 @@
}
@Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
+ }
+
+ @Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
}
@@ -1212,7 +1481,8 @@
private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
private static final int DO_ON_KEY_EVENT = 6;
private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
- private static final int DO_GESTURE_COMPLETE = 8;
+ private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
+ private static final int DO_GESTURE_COMPLETE = 9;
private final HandlerCaller mCaller;
@@ -1271,6 +1541,12 @@
mCaller.sendMessage(message);
}
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ final Message message =
+ mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
+ mCaller.sendMessage(message);
+ }
+
public void onPerformGestureResult(int sequence, boolean successfully) {
Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
successfully ? 1 : 0);
@@ -1361,6 +1637,11 @@
mCallback.onMagnificationChanged(region, scale, centerX, centerY);
} return;
+ case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
+ final int showMode = (int) message.arg1;
+ mCallback.onSoftKeyboardShowModeChanged(showMode);
+ } return;
+
case DO_GESTURE_COMPLETE: {
final boolean successfully = message.arg2 == 1;
mCallback.onPerformGestureResult(message.arg1, successfully);
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 6280542..ef05d6f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -43,5 +43,7 @@
void onMagnificationChanged(in Region region, float scale, float centerX, float centerY);
+ void onSoftKeyboardShowModeChanged(int showMode);
+
void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e58ef2f..d5e8a11 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -84,5 +84,9 @@
void setMagnificationCallbackEnabled(boolean enabled);
+ boolean setSoftKeyboardShowMode(int showMode);
+
+ void setSoftKeyboardCallbackEnabled(boolean enabled);
+
void sendMotionEvents(int sequence, in ParceledListSlice events);
}
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..99c275c 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;
@@ -4659,6 +4660,16 @@
}
}
+ /**
+ * Public entrypoint to stop profiling. This is required to end profiling when the app crashes,
+ * so that profiler data won't be lost.
+ *
+ * @hide
+ */
+ public void stopProfiling() {
+ mProfiler.stopProfiling();
+ }
+
static final void handleDumpHeap(boolean managed, DumpHeapData dhd) {
if (managed) {
try {
@@ -4959,16 +4970,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/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 7a0e7f6..fa0fbd1 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -35,10 +35,16 @@
* 'which' is some combination of:
* FLAG_SET_SYSTEM
* FLAG_SET_LOCK
+ *
+ * A 'null' cropHint rectangle is explicitly permitted as a sentinel for "whatever
+ * the source image's bounding rect is."
+ *
+ * The completion callback's "onWallpaperChanged()" method is invoked when the
+ * new wallpaper content is ready to display.
*/
ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
- out Bundle extras, int which);
-
+ in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+
/**
* Set the live wallpaper. This only affects the system wallpaper.
*/
@@ -54,14 +60,14 @@
*/
ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
out Bundle outParams);
-
+
/**
* If the current system wallpaper is a live wallpaper component, return the
* information about that wallpaper. Otherwise, if it is a static image,
* simply return null.
*/
WallpaperInfo getWallpaperInfo();
-
+
/**
* Clear the system wallpaper.
*/
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/Notification.java b/core/java/android/app/Notification.java
index 0f3aad9..7f037f2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4384,7 +4384,17 @@
view.addView(com.android.internal.R.id.media_actions, button);
}
}
- handleImage(view /* addPaddingToMainColumn */);
+ handleImage(view);
+ // handle the content margin
+ int endMargin;
+ if (mBuilder.mN.mLargeIcon != null) {
+ endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin_media);
+ } else {
+ endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_margin_end);
+ }
+ view.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
return view;
}
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..5ec59b4 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.
@@ -1033,6 +1088,11 @@
}
@Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ /* do nothing */
+ }
+
+ @Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
/* do nothing */
}
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/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f103576..b0ffd21 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -64,6 +64,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Provides access to the system wallpaper. With WallpaperManager, you can
@@ -770,18 +772,26 @@
return 0;
}
final Bundle result = new Bundle();
+ final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
Resources resources = mContext.getResources();
/* Set the wallpaper to the default values */
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
"res:" + resources.getResourceName(resid),
- mContext.getOpPackageName(), result, which);
+ mContext.getOpPackageName(), null, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
+ boolean ok = false;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
+ // The 'close()' is the trigger for any server-side image manipulation,
+ // so we must do that before waiting for completion.
+ fos.close();
+ completion.waitForCompletion();
} finally {
+ // Might be redundant but completion shouldn't wait unless the write
+ // succeeded; this is a fallback if it threw past the close+wait.
IoUtils.closeQuietly(fos);
}
}
@@ -876,14 +886,17 @@
return 0;
}
final Bundle result = new Bundle();
+ final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
- mContext.getOpPackageName(), result, which);
+ mContext.getOpPackageName(), visibleCropHint, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ fos.close();
+ completion.waitForCompletion();
} finally {
IoUtils.closeQuietly(fos);
}
@@ -990,14 +1003,17 @@
return 0;
}
final Bundle result = new Bundle();
+ final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
- mContext.getOpPackageName(), result, which);
+ mContext.getOpPackageName(), visibleCropHint, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
copyStreamToWallpaperFile(bitmapData, fos);
+ fos.close();
+ completion.waitForCompletion();
} finally {
IoUtils.closeQuietly(fos);
}
@@ -1385,4 +1401,28 @@
return null;
}
+
+ // Private completion callback for setWallpaper() synchronization
+ private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
+ final CountDownLatch mLatch;
+
+ public WallpaperSetCompletion() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ public void waitForCompletion() {
+ try {
+ mLatch.await(30, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ // This might be legit: the crop may take a very long time. Don't sweat
+ // it in that case; we are okay with display lagging behind in order to
+ // keep the caller from locking up indeterminately.
+ }
+ }
+
+ @Override
+ public void onWallpaperChanged() throws RemoteException {
+ mLatch.countDown();
+ }
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e4e97a1..c79c407 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,10 @@
* <p>If the device owner information contains only whitespaces then the message on the lock
* screen will be blank and the user will not be allowed to change it.
*
+ * <p>If the device owner information needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user
* owner info.
@@ -5211,6 +5215,10 @@
* for support."
* If the message is longer than 200 characters it may be truncated.
*
+ * <p>If the short support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setLongSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5250,6 +5258,10 @@
* Called by a device admin to set the long support message. This will
* be displayed to the user in the device administators settings screen.
*
+ * <p>If the long support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setShortSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5414,6 +5426,58 @@
}
/**
+ * Called by a profile owner of a managed profile to set the name of the organization under
+ * management.
+ *
+ * <p>If the organization name needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param title The organization name or {@code null} to clear a previously set name.
+ */
+ public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+ try {
+ mService.setOrganizationName(admin, title);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ }
+ }
+
+ /**
+ * Called by a profile owner of a managed profile to retrieve the name of the organization
+ * under management.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The organization name or {@code null} if none is set.
+ */
+ public String getOrganizationName(@NonNull ComponentName admin) {
+ try {
+ return mService.getOrganizationName(admin);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the default title message used in the confirm credentials screen for a given user.
+ *
+ * @param userHandle The user id of the user we're interested in.
+ * @return The organization name or {@code null} if none is set.
+ *
+ * @hide
+ */
+ public String getOrganizationNameForUser(int userHandle) {
+ try {
+ return mService.getOrganizationNameForUser(userHandle);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
* @return the {@link UserProvisioningState} for the current user - for unmanaged users will
* return {@link #STATE_USER_UNMANAGED}
* @hide
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6333013..37d13e5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -276,6 +276,10 @@
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
+ void setOrganizationName(in ComponentName admin, in String title);
+ String getOrganizationName(in ComponentName admin);
+ String getOrganizationNameForUser(int userHandle);
+
int getUserProvisioningState();
void setUserProvisioningState(int state, int userHandle);
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index d263646..5622207 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -151,21 +151,6 @@
public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
/**
- * Combined usage across all metering states.
- */
- public static final int METERING_ALL = -1;
-
- /**
- * Usage not accounted for in any other metering state.
- */
- public static final int METERING_DEFAULT = 0x1;
-
- /**
- * Metered usage.
- */
- public static final int METERING_METERED = 0x2;
-
- /**
* Combined usage across all roaming states.
*/
public static final int ROAMING_ALL = -1;
@@ -182,7 +167,6 @@
private int mUid;
private int mState;
- private int mMetering;
private int mRoaming;
private long mBeginTimeStamp;
private long mEndTimeStamp;
@@ -247,18 +231,6 @@
}
/**
- * Metering state. One of the following values:<p/>
- * <ul>
- * <li>{@link #METERING_ALL}</li>
- * <li>{@link #METERING_DEFAULT}</li>
- * <li>{@link #METERING_METERED}</li>
- * </ul>
- */
- public int getMetering() {
- return mMetering;
- }
-
- /**
* Roaming state. One of the following values:<p/>
* <ul>
* <li>{@link #ROAMING_ALL}</li>
@@ -463,8 +435,6 @@
private void fillBucketFromSummaryEntry(Bucket bucketOut) {
bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
- // TODO: Implement metering tracking.
- bucketOut.mMetering = Bucket.METERING_ALL;
bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
bucketOut.mBeginTimeStamp = mStartTimeStamp;
bucketOut.mEndTimeStamp = mEndTimeStamp;
@@ -512,7 +482,6 @@
mRecycledHistoryEntry);
bucketOut.mUid = Bucket.convertUid(getUid());
bucketOut.mState = Bucket.STATE_ALL;
- bucketOut.mMetering = Bucket.METERING_ALL;
bucketOut.mRoaming = Bucket.ROAMING_ALL;
bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0fce4e2..a88aa3125 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -165,14 +165,18 @@
mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
}
- if (right.mEndTimeStamp > mEndTimeStamp) {
+ if (right.mBeginTimeStamp > mBeginTimeStamp) {
+ // The incoming UsageStat begins after this one, so use its last time used fields
+ // as the source of truth.
+ // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+ // regards to their mEndTimeStamp.
mLastEvent = right.mLastEvent;
- mEndTimeStamp = right.mEndTimeStamp;
mLastTimeUsed = right.mLastTimeUsed;
mBeginIdleTime = right.mBeginIdleTime;
mLastTimeSystemUsed = right.mLastTimeSystemUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
+ mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
mLaunchCount += right.mLaunchCount;
}
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/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index aaa02bd..3a94bf7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3632,7 +3632,7 @@
* {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE},
* {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
* to modify the data returned.
- * @param userId The userId of the user being queried.
+ * @param userHandle UserHandle of the user being queried.
*
* @return Returns a List of ResolveInfo objects containing one entry for each
* matching receiver, ordered from best to worst. If there are no matching
@@ -3653,9 +3653,19 @@
*
* @hide
*/
+ @SystemApi
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ @ResolveInfoFlags int flags, UserHandle userHandle) {
+ return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
+ }
+
+ /**
+ * @hide
+ */
public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
+
/** {@hide} */
@Deprecated
public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9319c2e..44cd003 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3491,6 +3491,7 @@
info.maxRecents = target.info.maxRecents;
info.layout = target.info.layout;
info.resizeMode = target.info.resizeMode;
+ info.encryptionAware = target.info.encryptionAware;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
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/hardware/location/ContextHubInfo.aidl b/core/java/android/hardware/location/ContextHubInfo.aidl
new file mode 100644
index 0000000..1a9221a
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubInfo;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
new file mode 100644
index 0000000..e47c541
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -0,0 +1,351 @@
+/*
+ * 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.hardware.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubInfo {
+ private int mId;
+ private String mName;
+ private String mVendor;
+ private String mToolchain;
+ private int mPlatformVersion;
+ private int mStaticSwVersion;
+ private int mToolchainVersion;
+ private float mPeakMips;
+ private float mStoppedPowerDrawMw;
+ private float mSleepPowerDrawMw;
+ private float mPeakPowerDrawMw;
+
+ private int[] mSupportedSensors;
+
+ private MemoryRegion[] mMemoryRegions;
+
+ public ContextHubInfo() {
+ }
+
+ /**
+ * get the context hub unique identifer
+ *
+ * @return int - unique system wide identifier
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * set the context hub unique identifer
+ *
+ * @param id - unique system wide identifier for the hub
+ */
+ public void setId(int id) {
+ mId = id;
+ }
+
+ /**
+ * get a string as a hub name
+ *
+ * @return String - a name for the hub
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * set a string as the hub name
+ *
+ * @param String - the name for the hub
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * get a string as the vendor name
+ *
+ * @return String - a name for the vendor
+ */
+ public String getVendor() {
+ return mVendor;
+ }
+
+ /**
+ * set a string as the vendor name
+ *
+ * @param String - a name for the vendor
+ */
+ public void setVendor(String vendor) {
+ mVendor = vendor;
+ }
+
+ /**
+ * get tool chain string
+ *
+ * @return String - description of the tool chain
+ */
+ public String getToolchain() {
+ return mToolchain;
+ }
+
+ /**
+ * set tool chain string
+ *
+ * @param String - description of the tool chain
+ */
+ public void setToolchain(String toolchain) {
+ mToolchain = toolchain;
+ }
+
+ /**
+ * get platform version
+ *
+ * @return int - platform version number
+ */
+ public int getPlatformVersion() {
+ return mPlatformVersion;
+ }
+
+ /**
+ * set platform version
+ *
+ * @param platformVersion - platform version number
+ */
+ public void setPlatformVersion(int platformVersion) {
+ mPlatformVersion = platformVersion;
+ }
+
+ /**
+ * get static platform version number
+ *
+ * @return int - platform version number
+ */
+ public int getStaticSwVersion() {
+ return mStaticSwVersion;
+ }
+
+ /**
+ * set platform software version
+ *
+ * @param staticSwVersion - platform static s/w version number
+ */
+ public void setStaticSwVersion(int staticSwVersion) {
+ mStaticSwVersion = staticSwVersion;
+ }
+
+ /**
+ * get the tool chain version
+ *
+ * @return int - the tool chain version
+ */
+ public int getToolchainVersion() {
+ return mToolchainVersion;
+ }
+
+ /**
+ * set the tool chain version number
+ *
+ * @param toolchainVersion - tool chain version number
+ */
+ public void setToolchainVersion(int toolchainVersion) {
+ mToolchainVersion = toolchainVersion;
+ }
+
+ /**
+ * get the peak processing mips the hub can support
+ *
+ * @return float - peak MIPS that this hub can deliver
+ */
+ public float getPeakMips() {
+ return mPeakMips;
+ }
+
+ /**
+ * set the peak mips that this hub can support
+ *
+ * @param peakMips - peak mips this hub can deliver
+ */
+ public void setPeakMips(float peakMips) {
+ mPeakMips = peakMips;
+ }
+
+ /**
+ * get the stopped power draw in milliwatts
+ * This assumes that the hub enter a stopped state - which is
+ * different from the sleep state. Latencies on exiting the
+ * sleep state are typically higher and expect to be in multiple
+ * milliseconds.
+ *
+ * @return float - power draw by the hub in stopped state
+ */
+ public float getStoppedPowerDrawMw() {
+ return mStoppedPowerDrawMw;
+ }
+
+ /**
+ * Set the power consumed by the hub in stopped state
+ *
+ * @param stoppedPowerDrawMw - stopped power in milli watts
+ */
+ public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
+ mStoppedPowerDrawMw = stoppedPowerDrawMw;
+ }
+
+ /**
+ * get the power draw of the hub in sleep mode. This assumes
+ * that the hub supports a sleep mode in which the power draw is
+ * lower than the power consumed when the hub is actively
+ * processing. As a guideline, assume that the hub should be
+ * able to enter sleep mode if it knows reliably on completion
+ * of some task that the next interrupt/scheduled work item is
+ * at least 250 milliseconds later.
+ *
+ * @return float - sleep power draw in milli watts
+ */
+ public float getSleepPowerDrawMw() {
+ return mSleepPowerDrawMw;
+ }
+
+ /**
+ * Set the sleep power draw in milliwatts
+ *
+ * @param sleepPowerDrawMw - sleep power draw in milliwatts.
+ */
+ public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
+ mSleepPowerDrawMw = sleepPowerDrawMw;
+ }
+
+ /**
+ * get the peak powe draw of the hub. This is the power consumed
+ * by the hub at maximum load.
+ *
+ * @return float - peak power draw
+ */
+ public float getPeakPowerDrawMw() {
+ return mPeakPowerDrawMw;
+ }
+
+ /**
+ * set the peak power draw of the hub
+ *
+ * @param peakPowerDrawMw - peak power draw of the hub in
+ * milliwatts.
+ */
+ public void setPeakPowerDrawMw(float peakPowerDrawMw) {
+ mPeakPowerDrawMw = peakPowerDrawMw;
+ }
+
+ /**
+ * get the sensors supported by this hub
+ *
+ * @return int[] - all the supported sensors on this hub
+ *
+ * @see ContextHubManager
+ */
+ public int[] getSupportedSensors() {
+ return Arrays.copyOf(mSupportedSensors, mSupportedSensors.length);
+ }
+
+ /**
+ * get the various memory regions on this hub
+ *
+ * @return MemoryRegion[] - all the memory regions on this hub
+ *
+ * @see MemoryRegion
+ */
+ public MemoryRegion[] getMemoryRegions() {
+ return Arrays.copyOf(mMemoryRegions, mMemoryRegions.length);
+ }
+
+ /**
+ * set the supported sensors on this hub
+ *
+ * @param supportedSensors - supported sensors on this hub
+ */
+ public void setSupportedSensors(int[] supportedSensors) {
+ mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
+ }
+
+ /**
+ * set memory regions for this hub
+ *
+ * @param memoryRegions - memory regions information
+ *
+ * @see MemoryRegion
+ */
+ public void setMemoryRegions(MemoryRegion[] memoryRegions) {
+ mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
+ }
+
+ private ContextHubInfo(Parcel in) {
+ mId = in.readInt();
+ mName = in.readString();
+ mVendor = in.readString();
+ mToolchain = in.readString();
+ mPlatformVersion = in.readInt();
+ mToolchainVersion = in.readInt();
+ mStaticSwVersion = in.readInt();
+ mPeakMips = in.readFloat();
+ mStoppedPowerDrawMw = in.readFloat();
+ mSleepPowerDrawMw = in.readFloat();
+ mPeakPowerDrawMw = in.readFloat();
+
+ int numSupportedSensors = in.readInt();
+ mSupportedSensors = new int[numSupportedSensors];
+ in.readIntArray(mSupportedSensors);
+ mMemoryRegions = in.createTypedArray(MemoryRegion.CREATOR);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeString(mName);
+ out.writeString(mVendor);
+ out.writeString(mToolchain);
+ out.writeInt(mPlatformVersion);
+ out.writeInt(mToolchainVersion);
+ out.writeInt(mStaticSwVersion);
+ out.writeFloat(mPeakMips);
+ out.writeFloat(mStoppedPowerDrawMw);
+ out.writeFloat(mSleepPowerDrawMw);
+ out.writeFloat(mPeakPowerDrawMw);
+
+ out.writeInt(mSupportedSensors.length);
+ out.writeIntArray(mSupportedSensors);
+ out.writeTypedArray(mMemoryRegions, flags);
+ }
+
+ public static final Parcelable.Creator<ContextHubInfo> CREATOR
+ = new Parcelable.Creator<ContextHubInfo>() {
+ public ContextHubInfo createFromParcel(Parcel in) {
+ return new ContextHubInfo(in);
+ }
+
+ public ContextHubInfo[] newArray(int size) {
+ return new ContextHubInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
new file mode 100644
index 0000000..301b2e4
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -0,0 +1,278 @@
+/*
+ * 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.hardware.location;
+
+import android.annotation.SystemApi;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.Manifest;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A class that exposes the Context hubs on a device to
+ * applicaions.
+ *
+ * Please not that this class is not expected to be used by
+ * unbundled applications. Also, calling applications are
+ * expected to have LOCTION_HARDWARE premissions to use this
+ * class.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContextHubManager {
+
+ private static final String TAG = "ContextHubManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+ private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
+
+ private Context mContext;
+ private IContextHubService mContextHubService;
+ private boolean mContextHubConnected;
+
+ /**
+ * A special context hub identifer meaning any possible hub on
+ * the system.
+ */
+ public static final int ANY_HUB = -1;
+ /**
+ * A constant denoting a message to load a a Nano App
+ */
+ public static final int MSG_LOAD_NANO_APP = 1;
+ /**
+ * A constant denoting a message to unload a a Nano App
+ */
+ public static final int MSG_UNLOAD_NANO_APP = 2;
+ /**
+ * A constant denoting a message to send a message
+ */
+ public static final int MSG_DATA_SEND = 3;
+
+
+ /**
+ * Get a handle to all the context hubs in the system
+ * @return array of context hub handles
+ */
+ public int[] getContexthubHandles() {
+ int[] retVal = null;
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getContextHubHandles();
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch context hub handles :" + e.toString());
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * Get more information about a specific hub.
+ *
+ * @param contexthubHandle Handle of context hub
+ *
+ * @return ContextHubInfo returned information about the hub
+ *
+ * @see ContextHubInfo
+ */
+ public ContextHubInfo getContexthubInfo(int contexthubHandle) {
+ ContextHubInfo retVal = null;
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getContextHubInfo(contexthubHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch context hub info :" + e.toString());
+ }
+ }
+
+ return(retVal);
+ }
+
+ /**
+ * Load a nanoapp on a specified context hub
+ *
+ * @param hubHandle handle of context hub to load the app on.
+ * @param app the nanoApp to load on the hub
+ *
+ * @return int nanoAppInstance of the loaded nanoApp on success,
+ * -1 otherwise
+ *
+ * @see NanoApp
+ */
+ public int loadNanoApp(int hubHandle, NanoApp app) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.loadNanoApp(hubHandle, app);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch load nanoApp :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Unload a specified nanoApp
+ *
+ * @param nanoAppInstanceHandle handle of the nanoApp to load
+ *
+ * @return int 0 on success, -1 otherewise
+ */
+ public int unloadNanoApp(int nanoAppInstanceHandle) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.unloadNanoApp(nanoAppInstanceHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch unload nanoApp :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * get information about the nano app instance
+ *
+ * @param nanoAppInstanceHandle handle of the nanoAppInstance
+ *
+ * @return NanoAppInstanceInfo Inforamtion about the nano app
+ * instance.
+ *
+ * @see NanoAppInstanceInfo
+ */
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+ NanoAppInstanceInfo retVal = null;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.getNanoAppInstanceInfo(nanoAppInstanceHandle);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch nanoApp info :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Find a specified nano app on the system
+ *
+ * @param hubHandle handle of hub to search for nano app
+ * @param filter filter specifying the search criteria for app
+ *
+ * @see NanoAppFilter
+ *
+ * @return Integer[] Array of handles to any found nano apps
+ */
+ public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+ int[] temp;
+ Integer[] retVal = null;
+
+ if(mContextHubConnected) {
+ try {
+ temp = mContextHubService.findNanoAppOnHub(hubHandle, filter);
+ retVal = new Integer[temp.length];
+ for (int i = 0; i < temp.length; i++) {
+ retVal[i] = temp[i];
+ }
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not query nanoApp instance :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Send a message to a spcific nano app instance on a context
+ * hub
+ *
+ *
+ * @param hubHandle handle of the hub to send the message to
+ * @param nanoAppHandle handle of the nano app to send to
+ * @param msg Message to be sent
+ *
+ * @see ContextHubMessage
+ *
+ * @return int 0 on success, -1 otherwise
+ */
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) {
+ int retVal = -1;
+
+ if(mContextHubConnected) {
+ try {
+ retVal = mContextHubService.sendMessage(hubHandle, nanoAppHandle, msg);
+ }catch (RemoteException e) {
+ Log.e (TAG, "Could not fetch send message :" + e.toString());
+ }
+ }
+
+ return retVal;
+ }
+
+ private void checkPermissions() {
+ mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ }
+
+ private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
+ @Override
+ public void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg) throws RemoteException {
+
+ }
+ };
+
+ private ContextHubManager(Context context) {
+ checkPermissions();
+ mContext = context;
+ mContextHubConnected = false;
+ }
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mContextHubService = IContextHubService.Stub.asInterface(service);
+ mContextHubConnected = true;
+
+ // Register our Callback
+ try {
+ mContextHubService.registerCallBack(mClientCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not register callback with context hub service :" + e.toString());
+ }
+ Log.d(TAG, "contexthub manager connected to " + name.toString());
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mContextHubService = null;
+ mContextHubConnected = false;
+ Log.d(TAG, "contexthub manager disconnected from " + name.toString());
+ }
+ };
+
+}
diff --git a/core/java/android/hardware/location/ContextHubMessage.aidl b/core/java/android/hardware/location/ContextHubMessage.aidl
new file mode 100644
index 0000000..915f1ec
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubMessage;
+
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
new file mode 100644
index 0000000..954e97d
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -0,0 +1,129 @@
+/*
+ * 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.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubMessage {
+ private int mType;
+ private int mVersion;
+ private byte[]mData;
+
+ /**
+ * Get the message type
+ *
+ * @return int - message type
+ */
+ public int getMsgType() {
+ return mType;
+ }
+
+ /**
+ * get message version
+ *
+ * @return int - message version
+ */
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * get message data
+ *
+ * @return byte[] - message data buffer
+ */
+ public byte[] getData() {
+ return Arrays.copyOf(mData, mData.length);
+ }
+
+ /**
+ * set message type
+ *
+ * @param msgType - message type
+ */
+ public void setMsgType(int msgType) {
+ mType = msgType;
+ }
+
+ /**
+ * Set message version
+ *
+ * @param version - message version
+ */
+ public void setVersion(int version) {
+ mVersion = version;
+ }
+
+ /**
+ * set message data
+ *
+ * @param data - message buffer
+ */
+ public void setMsgData(byte[] data) {
+ mData = Arrays.copyOf(data, data.length);
+ }
+
+ /**
+ * Constructor for a context hub message
+ *
+ * @param msgType - message type
+ * @param version - version
+ * @param data - message buffer
+ */
+ public ContextHubMessage(int msgType, int version, byte[] data) {
+ mType = msgType;
+ mVersion = version;
+ mData = Arrays.copyOf(data, data.length);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ private ContextHubMessage(Parcel in) {
+ mType = in.readInt();
+ mVersion = in.readInt();
+ byte[] byteBuffer = new byte[in.readInt()];
+ in.readByteArray(byteBuffer);
+ }
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mType);
+ out.writeInt(mVersion);
+ out.writeInt(mData.length);
+ out.writeByteArray(mData);
+ }
+
+ public static final Parcelable.Creator<ContextHubMessage> CREATOR
+ = new Parcelable.Creator<ContextHubMessage>() {
+ public ContextHubMessage createFromParcel(Parcel in) {
+ return new ContextHubMessage(in);
+ }
+
+ public ContextHubMessage[] newArray(int size) {
+ return new ContextHubMessage[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
new file mode 100644
index 0000000..a2a13c6
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -0,0 +1,203 @@
+/*
+ * 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.hardware.location;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class ContextHubService extends Service {
+
+ private static final String TAG = "ContextHubService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static ContextHubService sSingletonInstance;
+ private static final Object sSingletonInstanceLock = new Object();
+
+ private HashMap<Integer, ContextHubInfo> mHubHash;
+ private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
+ private ContextHubInfo[] mContexthubInfo;
+
+
+ private native int nativeSendMessage(int[] header, byte[] data);
+ private native ContextHubInfo[] nativeInitialize();
+
+ private int onMessageReceipt(int[] header, byte[] data) {
+ return 0;
+ }
+ private void initialize() {
+ mContexthubInfo = nativeInitialize();
+
+ mHubHash = new HashMap<Integer, ContextHubInfo>();
+
+ for (int i = 0; i < mContexthubInfo.length; i++) {
+ mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
+ }
+ }
+
+ private ContextHubService(Context context) {
+ initialize();
+ Log.d(TAG, "Created from " + context.toString());
+ }
+
+ public static ContextHubService getInstance(Context context) {
+ synchronized (sSingletonInstanceLock) {
+ if (sSingletonInstance == null) {
+ sSingletonInstance = new ContextHubService(context);
+ }
+ return sSingletonInstance;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
+
+ private IContextHubCallback callback;
+
+ @Override
+ public int registerCallBack(IContextHubCallback callback) throws RemoteException{
+ this.callback = callback;
+ return 0;
+ }
+
+ @Override
+ public int[] getContextHubHandles() throws RemoteException {
+ int [] returnArray = new int[mHubHash.size()];
+ int i = 0;
+ for (int key : mHubHash.keySet()) {
+ // Add any filtering here
+ returnArray[i] = key;
+ i++;
+ }
+ return returnArray;
+ }
+
+ @Override
+ public ContextHubInfo getContextHubInfo(int contexthubHandle) throws RemoteException {
+ return mHubHash.get(contexthubHandle);
+ }
+
+ @Override
+ public int loadNanoApp(int hubHandle, NanoApp app) throws RemoteException {
+ if (!mHubHash.containsKey(hubHandle)) {
+ return -1;
+ } else {
+ // Call Native interface here
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_LOAD_NANO_APP;
+ msgHeader[1] = app.getAppId();
+ msgHeader[2] = app.getAppVersion();
+ msgHeader[3] = 0; // LOADING_HINTS
+ msgHeader[4] = hubHandle;
+
+ int handle = nativeSendMessage(msgHeader, app.getAppBinary());
+
+ // if successful, add an entry to mNanoAppHash
+
+ if(handle > 0) {
+ return 0;
+ } else {
+
+ return -1;
+ }
+ }
+ }
+
+ @Override
+ public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+ if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+ return -1;
+ } else {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
+ // Call Native interface here
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_UNLOAD_NANO_APP;
+ msgHeader[1] = info.getContexthubId();
+ msgHeader[2] = info.getHandle();
+
+ int result = nativeSendMessage(msgHeader, null);
+ // if successful, remove the entry in mNanoAppHash
+ if(result == 0) {
+ mNanoAppHash.remove(nanoAppInstanceHandle);
+ }
+ return(result);
+ }
+ }
+
+ @Override
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
+ // This assumes that all the nanoAppInfo is current. This is reasonable
+ // for the use cases for tightly controlled nanoApps.
+ //
+ if(!mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
+ return(mNanoAppHash.get(nanoAppInstanceHandle));
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+ ArrayList<Integer> foundInstances = new ArrayList<Integer>();
+
+ for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
+ NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
+
+ if(filter.testMatch(info)){
+ foundInstances.add(nanoAppInstance);
+ }
+ }
+
+ int[] retArray = new int[foundInstances.size()];
+ for (int i = 0; i < foundInstances.size(); i++) {
+ retArray[i] = foundInstances.get(i).intValue();
+ }
+
+ return retArray;
+ }
+
+ @Override
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
+ int[] msgHeader = new int[8];
+ msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
+ msgHeader[1] = hubHandle;
+ msgHeader[2] = nanoAppHandle;
+ msgHeader[3] = msg.getMsgType();
+ msgHeader[4] = msg.getVersion();
+
+ return (nativeSendMessage(msgHeader, msg.getData()));
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/IContextHubCallback.aidl b/core/java/android/hardware/location/IContextHubCallback.aidl
new file mode 100644
index 0000000..45b1ef4
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.hardware.location;
+
+import android.hardware.location.ContextHubMessage;
+
+/** @hide */
+oneway interface IContextHubCallback {
+ void onMessageReceipt(int hubId, int nanoAppId, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
new file mode 100644
index 0000000..b2db0b2
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.hardware.location;
+
+// Declare any non-default types here with import statements
+import android.hardware.location.ContextHubMessage;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.IContextHubCallback;
+
+/** @hide */
+interface IContextHubService {
+
+ // register a callback to receive messages
+ int registerCallBack(in IContextHubCallback callback);
+
+ // Gets a list of available context hub handles
+ int[] getContextHubHandles();
+
+ // Get the properties of a hub
+ ContextHubInfo getContextHubInfo(int contextHubHandle);
+
+ // Load a nanoapp on a specified context hub
+ int loadNanoApp(int hubHandle, in NanoApp app);
+
+ // Unload a nanoapp instance
+ int unloadNanoApp(int nanoAppInstanceHandle);
+
+ // get information about a nanoAppInstance
+ NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
+
+ // find all nanoApp instances matching some filter
+ int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
+
+ // send a message to a nanoApp
+ int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
new file mode 100644
index 0000000..e8c7615
--- /dev/null
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -0,0 +1,115 @@
+/*
+ * 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.hardware.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+
+@SystemApi
+public class MemoryRegion implements Parcelable{
+
+ private int mSizeBytes;
+ private int mSizeBytesFree;
+ private boolean mIsReadable;
+ private boolean mIsWritable;
+ private boolean mIsExecutable;
+
+ /**
+ * get the capacity of the memory region in bytes
+ *
+ * @return int - the memory capacity in bytes
+ */
+ public int getCapacityBytes() {
+ return mSizeBytes;
+ }
+
+ /**
+ * get the free capacity of the memory region in bytes
+ *
+ * @return int - free bytes
+ */
+ public int getFreeCapacityBytes() {
+ return mSizeBytesFree;
+ }
+
+ /**
+ * Is the memory readable
+ *
+ * @return boolean - true if memory is readable, false otherwise
+ */
+ public boolean isReadable() {
+ return mIsReadable;
+ }
+
+ /**
+ * Is the memory writable
+ *
+ * @return boolean - true if memory is writable, false otherwise
+ */
+ public boolean isWritable() {
+ return mIsWritable;
+ }
+
+ /**
+ * Is the memory executable
+ *
+ * @return boolean - true if memory is executable, false
+ * otherwise
+ */
+ public boolean isExecutable() {
+ return mIsExecutable;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSizeBytes);
+ dest.writeInt(mSizeBytesFree);
+ dest.writeInt(mIsReadable ? 1 : 0);
+ dest.writeInt(mIsWritable ? 1 : 0);
+ dest.writeInt(mIsExecutable ? 1 : 0);
+ }
+
+ public MemoryRegion(Parcel source) {
+ mSizeBytes = source.readInt();
+ mSizeBytesFree = source.readInt();
+ mIsReadable = source.readInt() != 0;
+ mIsWritable = source.readInt() != 0;
+ mIsExecutable = source.readInt() != 0;
+ }
+
+ public static final Parcelable.Creator<MemoryRegion> CREATOR
+ = new Parcelable.Creator<MemoryRegion>() {
+ public MemoryRegion createFromParcel(Parcel in) {
+ return new MemoryRegion(in);
+ }
+
+ public MemoryRegion[] newArray(int size) {
+ return new MemoryRegion[size];
+ }
+ };
+
+}
diff --git a/core/java/android/hardware/location/NanoApp.aidl b/core/java/android/hardware/location/NanoApp.aidl
new file mode 100644
index 0000000..d32c44a
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.hardware.location;
+/*
+@hide
+*/
+parcelable NanoApp;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
new file mode 100644
index 0000000..36d181f
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -0,0 +1,290 @@
+/*
+ * 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.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class describing nano apps.
+ * A nano app is a piece of executable code that can be
+ * downloaded onto a specific architecture. These are targtted
+ * for low power compute domains on a device.
+ *
+ * Nano apps are expected to be used only by bundled apps only
+ * at this time.
+ *
+ * @hide
+ */
+@SystemApi
+public class NanoApp {
+ private String mPublisher;
+ private String mName;
+
+ private int mAppId;
+ private int mAppVersion;
+
+ private int mNeededReadMemBytes;
+ private int mNeededWriteMemBytes;
+ private int mNeededExecMemBytes;
+
+ private int[] mNeededSensors;
+ private int[] mOutputEvents;
+ private byte[] mAppBinary;
+
+ public NanoApp() {
+ }
+
+ /**
+ * Set the publisher name
+ *
+ * @param publisher name of the publisher of this nano app
+ */
+ public void setPublisher(String publisher) {
+ mPublisher = publisher;
+ }
+
+ /**
+ * set the name of the app
+ *
+ * @param name name of the app
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * set the app identifier
+ *
+ * @param appId add identifier
+ */
+ public void setAppId(int appId) {
+ mAppId = appId;
+ }
+
+ /**
+ * Set the app version
+ *
+ * @param appVersion app version
+ */
+ public void setAppVersion(int appVersion) {
+ mAppVersion = appVersion;
+ }
+
+ /**
+ * set memory needed as read only
+ *
+ * @param neededReadMemBytes
+ * read only memory needed in bytes
+ */
+ public void setNeededReadMemBytes(int neededReadMemBytes) {
+ mNeededReadMemBytes = neededReadMemBytes;
+ }
+
+ /**
+ * set writable memory needed in bytes
+ *
+ * @param neededWriteMemBytes
+ * writable memory needed in bytes
+ */
+ public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+ mNeededWriteMemBytes = neededWriteMemBytes;
+ }
+
+ /**
+ * set executable memory needed
+ *
+ * @param neededExecMemBytes
+ * executable memory needed in bytes
+ */
+ public void setNeededExecMemBytes(int neededExecMemBytes) {
+ mNeededExecMemBytes = neededExecMemBytes;
+ }
+
+ /**
+ * set the sensors needed for this app
+ *
+ * @param neededSensors
+ * needed Sensors
+ */
+ public void setNeededSensors(int[] neededSensors) {
+ mNeededSensors = neededSensors;
+ }
+
+ public void setOutputEvents(int[] outputEvents) {
+ mOutputEvents = outputEvents;
+ }
+
+ /**
+ * set output events returned by the nano app
+ *
+ * @param appBinary generated events
+ */
+ public void setAppBinary(byte[] appBinary) {
+ mAppBinary = appBinary;
+ }
+
+
+ /**
+ * get the publisher name
+ *
+ * @return publisher name
+ */
+ public String getPublisher() {
+ return mPublisher;
+ }
+
+ /**
+ * get the name of the app
+ *
+ * @return app name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * get the identifier of the app
+ *
+ * @return identifier for this app
+ */
+ public int getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * get the app version
+ *
+ * @return app version
+ */
+ public int getAppVersion() {
+ return mAppVersion;
+ }
+
+ /**
+ * get the ammount of readable memory needed by this app
+ *
+ * @return readable memory needed in bytes
+ */
+ public int getNeededReadMemBytes() {
+ return mNeededReadMemBytes;
+ }
+
+ /**
+ * get the ammount og writable memory needed in bytes
+ *
+ * @return writable memory needed in bytes
+ */
+ public int getNeededWriteMemBytes() {
+ return mNeededWriteMemBytes;
+ }
+
+ /**
+ * executable memory needed in bytes
+ *
+ * @return executable memory needed in bytes
+ */
+ public int getNeededExecMemBytes() {
+ return mNeededExecMemBytes;
+ }
+
+ /**
+ * get the sensors needed by this app
+ *
+ * @return sensors needed
+ */
+ public int[] getNeededSensors() {
+ return mNeededSensors;
+ }
+
+ /**
+ * get the events generated by this app
+ *
+ * @return generated events
+ */
+ public int[] getOutputEvents() {
+ return mOutputEvents;
+ }
+
+ /**
+ * get the binary for this app
+ *
+ * @return app binary
+ */
+ public byte[] getAppBinary() {
+ return mAppBinary;
+ }
+
+ private NanoApp(Parcel in) {
+ mPublisher = in.readString();
+ mName = in.readString();
+
+ mAppId = in.readInt();
+ mAppVersion = in.readInt();
+ mNeededReadMemBytes = in.readInt();
+ mNeededWriteMemBytes = in.readInt();
+ mNeededExecMemBytes = in.readInt();
+
+ int mNeededSensorsLength = in.readInt();
+ mNeededSensors = new int[mNeededSensorsLength];
+ in.readIntArray(mNeededSensors);
+
+ int mOutputEventsLength = in.readInt();
+ mOutputEvents = new int[mOutputEventsLength];
+ in.readIntArray(mOutputEvents);
+
+ int binaryLength = in.readInt();
+ mAppBinary = new byte[binaryLength];
+ in.readByteArray(mAppBinary);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPublisher);
+ out.writeString(mName);
+ out.writeInt(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mNeededReadMemBytes);
+ out.writeInt(mNeededWriteMemBytes);
+ out.writeInt(mNeededExecMemBytes);
+
+ out.writeInt(mNeededSensors.length);
+ out.writeIntArray(mNeededSensors);
+
+ out.writeInt(mOutputEvents.length);
+ out.writeIntArray(mOutputEvents);
+
+ out.writeInt(mAppBinary.length);
+ out.writeByteArray(mAppBinary);
+ }
+
+ public static final Parcelable.Creator<NanoApp> CREATOR
+ = new Parcelable.Creator<NanoApp>() {
+ public NanoApp createFromParcel(Parcel in) {
+ return new NanoApp(in);
+ }
+
+ public NanoApp[] newArray(int size) {
+ return new NanoApp[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.aidl b/core/java/android/hardware/location/NanoAppFilter.aidl
new file mode 100644
index 0000000..cc6d475
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.hardware.location;
+/*
+@hide
+*/
+parcelable NanoAppFilter;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
new file mode 100644
index 0000000..ac341e4
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -0,0 +1,139 @@
+/*
+ * 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.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppFilter {
+
+ // The appId, can be set to APP_ID_ANY
+ private long mAppId;
+
+ // Version to filter apps
+ private int mAppVersion;
+
+ // filtering spec for version
+ private int mVersionRestrictionMask;
+
+ // If APP_ID is any, then a match is performef with the vendor mask
+ private long mAppIdVendorMask;
+
+ // Id of the context hub this instance is expected on
+ private int mContextHubId;
+
+ /**
+ * Flag indicating any version. With this flag set, all versions shall match provided version.
+ */
+ public static final int FLAGS_VERSION_ANY = -1;
+ /**
+ * If this flag is set, only versions strictly greater than the version specified shall match.
+ */
+ public static final int FLAGS_VERSION_GREAT_THAN = 2;
+ /**
+ * If this flag is set, only versions strictly less than the version specified shall match.
+ */
+ public static final int FLAGS_VERSION_LESS_THAN = 4;
+ public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
+
+ /**
+ * If this flag is set, only versions strictly equal to the version specified shall match.
+ */
+ public static final int APP_ANY = -1;
+
+ /**
+ * If this flag is set, all vendors shall match.
+ */
+ public static final int VENDOR_ANY = -1;
+
+ /**
+ * If this flag is set, any hub shall match.
+ */
+ public static final int HUB_ANY = -1;
+
+ private NanoAppFilter(Parcel in) {
+ mAppId = in.readLong();
+ mAppVersion = in.readInt();
+ mVersionRestrictionMask = in.readInt();
+ mAppIdVendorMask = in.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+
+ out.writeLong(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mVersionRestrictionMask);
+ out.writeLong(mAppIdVendorMask);
+ }
+
+ /**
+ * Create a filter
+ *
+ * @param appId application id
+ * @param appVersion application version
+ * @param versionMask version
+ * @param vendorMask vendor
+ */
+ public NanoAppFilter(long appId, int appVersion, int versionMask, long vendorMask) {
+ mAppId = appId;
+ mAppVersion = appVersion;
+ mVersionRestrictionMask = versionMask;
+ mAppIdVendorMask = vendorMask;
+ }
+
+ private boolean versionsMatch(int versionRestrictionMask, int expected, int actual){
+ // some refactoring of version restriction mask is needed, until then, return all
+ return true;
+ }
+ /**
+ *
+ * @param nano app instance info
+ *
+ * @return true if this is a match, false otherwise
+ */
+ public boolean testMatch(NanoAppInstanceInfo info) {
+ if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+ (mAppId == APP_ANY || info.getAppId() == mAppId) &&
+ // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
+ (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static final Parcelable.Creator<NanoAppFilter> CREATOR
+ = new Parcelable.Creator<NanoAppFilter>() {
+ public NanoAppFilter createFromParcel(Parcel in) {
+ return new NanoAppFilter(in);
+ }
+
+ public NanoAppFilter[] newArray(int size) {
+ return new NanoAppFilter[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
new file mode 100644
index 0000000..c8c40d7
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.hardware.location;
+/*
+@hide
+*/
+parcelable NanoAppInstanceInfo;
\ No newline at end of file
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
new file mode 100644
index 0000000..ac62919
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -0,0 +1,302 @@
+/*
+ * 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.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppInstanceInfo {
+ private String mPublisher;
+ private String mName;
+
+ private int mAppId;
+ private int mAppVersion;
+
+ private int mNeededReadMemBytes;
+ private int mNeededWriteMemBytes;
+ private int mNeededExecMemBytes;
+
+ private int[] mNeededSensors;
+ private int[] mOutputEvents;
+
+ private int mContexthubId;
+ private int mHandle;
+
+ public NanoAppInstanceInfo() {
+ }
+
+ /**
+ * get the publisher of this app
+ *
+ * @return String - name of the publisher
+ */
+ public String getPublisher() {
+ return mPublisher;
+ }
+
+
+ /**
+ * set the publisher name for the app
+ *
+ * @param publisher - name of the publisher
+ */
+ public void setPublisher(String publisher) {
+ mPublisher = publisher;
+ }
+
+ /**
+ * get the name of the app
+ *
+ * @return String - name of the app
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * set the name of the app
+ *
+ * @param name - name of the app
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /**
+ * Get the application identifier
+ *
+ * @return int - application identifier
+ */
+ public int getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * Set the application identifier
+ *
+ * @param appId - application identifier
+ */
+ public void setAppId(int appId) {
+ mAppId = appId;
+ }
+
+ /**
+ * Set the application version
+ *
+ * @return int - version of the app
+ */
+ public int getAppVersion() {
+ return mAppVersion;
+ }
+
+ /**
+ * Set the application version
+ *
+ * @param appVersion - version of the app
+ */
+ public void setAppVersion(int appVersion) {
+ mAppVersion = appVersion;
+ }
+
+ /**
+ * Get the read memory needed by the app
+ *
+ * @return int - readable memory needed in bytes
+ */
+ public int getNeededReadMemBytes() {
+ return mNeededReadMemBytes;
+ }
+
+ /**
+ * Set the read memory needed by the app
+ *
+ * @param neededReadMemBytes - readable Memory needed in bytes
+ */
+ public void setNeededReadMemBytes(int neededReadMemBytes) {
+ mNeededReadMemBytes = neededReadMemBytes;
+ }
+
+ /**
+ * get writable memory needed by the app
+ *
+ * @return int - writable memory needed by the app
+ */
+ public int getNeededWriteMemBytes() {
+ return mNeededWriteMemBytes;
+ }
+
+ /**
+ * set writable memory needed by the app
+ *
+ * @param neededWriteMemBytes - writable memory needed by the
+ * app
+ */
+ public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+ mNeededWriteMemBytes = neededWriteMemBytes;
+ }
+
+ /**
+ * get executable memory needed by the app
+ *
+ * @return int - executable memory needed by the app
+ */
+ public int getNeededExecMemBytes() {
+ return mNeededExecMemBytes;
+ }
+
+ /**
+ * set executable memory needed by the app
+ *
+ * @param neededExecMemBytes - executable memory needed by the
+ * app
+ */
+ public void setNeededExecMemBytes(int neededExecMemBytes) {
+ mNeededExecMemBytes = neededExecMemBytes;
+ }
+
+ /**
+ * Get the sensors needed by this app
+ *
+ * @return int[] all the required sensors needed by this app
+ */
+ public int[] getNeededSensors() {
+ return mNeededSensors;
+ }
+
+ /**
+ * set the sensors needed by this app
+ *
+ * @param neededSensors - all the sensors needed by this app
+ */
+ public void setNeededSensors(int[] neededSensors) {
+ mNeededSensors = neededSensors;
+ }
+
+ /**
+ * get the events generated by this app
+ *
+ * @return all the events that can be generated by this app
+ */
+ public int[] getOutputEvents() {
+ return mOutputEvents;
+ }
+
+ /**
+ * set the output events that can be generated by this app
+ *
+ * @param outputEvents - the events that may be generated by
+ * this app
+ */
+ public void setOutputEvents(int[] outputEvents) {
+ mOutputEvents = outputEvents;
+ }
+
+ /**
+ * get the context hub identifier
+ *
+ * @return int - system unique hub identifier
+ */
+ public int getContexthubId() {
+ return mContexthubId;
+ }
+
+ /**
+ * set the context hub identifier
+ *
+ * @param contexthubId - system wide unique identifier
+ */
+ public void setContexthubId(int contexthubId) {
+ mContexthubId = contexthubId;
+ }
+
+ /**
+ * get a handle to the nano app instance
+ *
+ * @return int - handle to this instance
+ */
+ public int getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * set the handle for an app instance
+ *
+ * @param handle - handle to this instance
+ */
+ public void setHandle(int handle) {
+ mHandle = handle;
+ }
+
+
+ private NanoAppInstanceInfo(Parcel in) {
+ mPublisher = in.readString();
+ mName = in.readString();
+
+ mAppId = in.readInt();
+ mAppVersion = in.readInt();
+ mNeededReadMemBytes = in.readInt();
+ mNeededWriteMemBytes = in.readInt();
+ mNeededExecMemBytes = in.readInt();
+
+ int mNeededSensorsLength = in.readInt();
+ mNeededSensors = new int[mNeededSensorsLength];
+ in.readIntArray(mNeededSensors);
+
+ int mOutputEventsLength = in.readInt();
+ mOutputEvents = new int[mOutputEventsLength];
+ in.readIntArray(mOutputEvents);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPublisher);
+ out.writeString(mName);
+ out.writeInt(mAppId);
+ out.writeInt(mAppVersion);
+ out.writeInt(mContexthubId);
+ out.writeInt(mNeededReadMemBytes);
+ out.writeInt(mNeededWriteMemBytes);
+ out.writeInt(mNeededExecMemBytes);
+
+ out.writeInt(mNeededSensors.length);
+ out.writeIntArray(mNeededSensors);
+
+ out.writeInt(mOutputEvents.length);
+ out.writeIntArray(mOutputEvents);
+
+ }
+
+ public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
+ = new Parcelable.Creator<NanoAppInstanceInfo>() {
+ public NanoAppInstanceInfo createFromParcel(Parcel in) {
+ return new NanoAppInstanceInfo(in);
+ }
+
+ public NanoAppInstanceInfo[] newArray(int size) {
+ return new NanoAppInstanceInfo[size];
+ }
+ };
+}
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/os/UserHandle.java b/core/java/android/os/UserHandle.java
index bcc1213..344d06e 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -144,6 +144,7 @@
}
/** @hide */
+ @SystemApi
public static UserHandle of(@UserIdInt int userId) {
return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 6321122..1ac798b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1382,7 +1382,7 @@
/**
* Returns information for all users on this device.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @return the list of users that were created.
+ * @return the list of users that exist on the device.
* @hide
*/
public List<UserInfo> getUsers() {
@@ -1395,6 +1395,29 @@
}
/**
+ * Returns serial numbers of all users on this device.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * @param excludeDying specify if the list should exclude users being removed.
+ * @return the list of serial numbers of users that exist on the device.
+ * @hide
+ */
+ @SystemApi
+ public long[] getSerialNumbersOfUsers(boolean excludeDying) {
+ try {
+ List<UserInfo> users = mService.getUsers(excludeDying);
+ long[] result = new long[users.size()];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = users.get(i).serialNumber;
+ }
+ return result;
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get users list", re);
+ return null;
+ }
+ }
+
+ /**
* @return the user's account name, null if not found.
* @hide
*/
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index fda6326..ebb12fd 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.annotation.SystemApi;
import android.annotation.XmlRes;
import android.app.Activity;
import android.content.Context;
@@ -24,8 +25,8 @@
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.Log;
@@ -110,7 +111,13 @@
* managed by this instance.
*/
private int mSharedPreferencesMode;
-
+
+ private static final int STORAGE_DEFAULT = 0;
+ private static final int STORAGE_DEVICE_ENCRYPTED = 1;
+ private static final int STORAGE_CREDENTIAL_ENCRYPTED = 2;
+
+ private int mStorage = STORAGE_DEFAULT;
+
/**
* The {@link PreferenceScreen} at the root of the preference hierarchy.
*/
@@ -343,6 +350,46 @@
}
/**
+ * Sets the storage location used internally by this class to be the default
+ * provided by the hosting {@link Context}.
+ */
+ public void setStorageDefault() {
+ mStorage = STORAGE_DEFAULT;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Explicitly set the storage location used internally by this class to be
+ * device-encrypted storage.
+ * <p>
+ * Data stored in device-encrypted storage is typically encrypted with a key
+ * tied to the physical device, and it can be accessed when the device has
+ * booted successfully, both <em>before and after</em> the user has
+ * authenticated with their credentials (such as a lock pattern or PIN).
+ * Because device-encrypted data is available before user authentication,
+ * you should carefully consider what data you store using this mode.
+ *
+ * @see Context#createDeviceEncryptedStorageContext()
+ */
+ public void setStorageDeviceEncrypted() {
+ mStorage = STORAGE_DEVICE_ENCRYPTED;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Explicitly set the storage location used internally by this class to be
+ * credential-encrypted storage.
+ *
+ * @see Context#createCredentialEncryptedStorageContext()
+ * @hide
+ */
+ @SystemApi
+ public void setStorageCredentialEncrypted() {
+ mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
+ mSharedPreferences = null;
+ }
+
+ /**
* Gets a SharedPreferences instance that preferences managed by this will
* use.
*
@@ -351,7 +398,20 @@
*/
public SharedPreferences getSharedPreferences() {
if (mSharedPreferences == null) {
- mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
+ final Context storageContext;
+ switch (mStorage) {
+ case STORAGE_DEVICE_ENCRYPTED:
+ storageContext = mContext.createDeviceEncryptedStorageContext();
+ break;
+ case STORAGE_CREDENTIAL_ENCRYPTED:
+ storageContext = mContext.createCredentialEncryptedStorageContext();
+ break;
+ default:
+ storageContext = mContext;
+ break;
+ }
+
+ mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
mSharedPreferencesMode);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bc0d7d6..6e92ec1 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -501,6 +501,23 @@
"android.settings.USER_DICTIONARY_SETTINGS";
/**
+ * Activity Action: Show settings to configure the hardware keyboard layout.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ *
+ * @see android.hardware.input.InputManager#ACTION_QUERY_KEYBOARD_LAYOUTS
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_KEYBOARD_LAYOUT_SETTINGS =
+ "android.settings.KEYBOARD_LAYOUT_SETTINGS";
+
+ /**
* Activity Action: Adds a word to the user dictionary.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -4839,6 +4856,29 @@
"accessibility_display_magnification_auto_update";
/**
+ * Setting that specifies what mode the soft keyboard is in (default or hidden). Can be
+ * modified from an AccessibilityService using the SoftKeyboardController.
+ *
+ * @hide
+ */
+ public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE =
+ "accessibility_soft_keyboard_mode";
+
+ /**
+ * Default soft keyboard behavior.
+ *
+ * @hide
+ */
+ public static final int SHOW_MODE_AUTO = 0;
+
+ /**
+ * Soft keyboard is never shown.
+ *
+ * @hide
+ */
+ public static final int SHOW_MODE_HIDDEN = 1;
+
+ /**
* Setting that specifies whether timed text (captions) should be
* displayed in video content. Text display properties are controlled by
* the following settings:
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/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 1c0ea0f..34713ad 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -25,8 +25,6 @@
import android.widget.RemoteViews;
import android.widget.TextView;
-import com.android.internal.R;
-
import java.util.ArrayList;
/**
@@ -39,6 +37,7 @@
public static final int NO_COLOR = -1;
private final int mHeaderMinWidth;
private final int mExpandTopPadding;
+ private final int mContentEndMargin;
private View mAppName;
private View mSubTextView;
private OnClickListener mExpandClickListener;
@@ -51,6 +50,7 @@
private int mOriginalNotificationColor;
private boolean mGroupHeader;
private boolean mExpanded;
+ private boolean mShowWorkBadgeAtEnd;
public NotificationHeaderView(Context context) {
this(context, null);
@@ -68,6 +68,8 @@
super(context, attrs, defStyleAttr, defStyleRes);
mHeaderMinWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_header_shrink_min_width);
+ mContentEndMargin = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
mExpandTopPadding = (int) (1 * getResources().getDisplayMetrics().density);
}
@@ -135,6 +137,9 @@
super.onLayout(changed, l, t, r, b);
if (mProfileBadge.getVisibility() != View.GONE) {
int paddingEnd = getPaddingEnd();
+ if (mShowWorkBadgeAtEnd) {
+ paddingEnd = mContentEndMargin;
+ }
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
mProfileBadge.layout(paddingEnd,
mProfileBadge.getTop(),
@@ -225,6 +230,17 @@
mExpandButton.setPadding(0, paddingTop, 0, 0);
}
+ public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
+ if (showWorkBadgeAtEnd != mShowWorkBadgeAtEnd) {
+ setClipToPadding(!showWorkBadgeAtEnd);
+ mShowWorkBadgeAtEnd = showWorkBadgeAtEnd;
+ }
+ }
+
+ public View getWorkProfileIcon() {
+ return mProfileBadge;
+ }
+
public class HeaderTouchListener implements View.OnTouchListener {
private final ArrayList<Rect> mTouchRects = new ArrayList<>();
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/WindowManager.java b/core/java/android/view/WindowManager.java
index 772eeec..0c5a5fc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -589,14 +589,14 @@
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
/**
- * Window type: Windows that are overlaid <em>only</em> by an {@link
+ * Window type: Windows that are overlaid <em>only</em> by a connected {@link
* android.accessibilityservice.AccessibilityService} for interception of
* user interactions without changing the windows an accessibility service
* can introspect. In particular, an accessibility service can introspect
* only windows that a sighted user can interact with which is they can touch
* these windows or can type into these windows. For example, if there
* is a full screen accessibility overlay that is touchable, the windows
- * below it will be introspectable by an accessibility service regardless
+ * below it will be introspectable by an accessibility service even though
* they are covered by a touchable window.
*/
public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1327ea1..b673386 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -38,8 +38,8 @@
/**
* This class represents a node of the window content as well as actions that
* can be requested from its source. From the point of view of an
- * {@link android.accessibilityservice.AccessibilityService} a window content is
- * presented as tree of accessibility node info which may or may not map one-to-one
+ * {@link android.accessibilityservice.AccessibilityService} a window's content is
+ * presented as a tree of accessibility node infos, which may or may not map one-to-one
* to the view hierarchy. In other words, a custom view is free to report itself as
* a tree of accessibility node info.
* </p>
@@ -50,7 +50,7 @@
* <p>
* Please refer to {@link android.accessibilityservice.AccessibilityService} for
* details about how to obtain a handle to window content as a tree of accessibility
- * node info as well as familiarizing with the security model.
+ * node info as well as details about the security model.
* </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
@@ -2422,18 +2422,30 @@
}
/**
- * Gets the text selection start.
+ * Gets the text selection start or the cursor position.
+ * <p>
+ * If no text is selected, both this method and
+ * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
+ * the current location of the cursor.
+ * </p>
*
- * @return The text selection start if there is selection or -1.
+ * @return The text selection start, the cursor location if there is no selection, or -1 if
+ * there is no text selection and no cursor.
*/
public int getTextSelectionStart() {
return mTextSelectionStart;
}
/**
- * Gets the text selection end.
+ * Gets the text selection end if text is selected.
+ * <p>
+ * If no text is selected, both this method and
+ * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
+ * the current location of the cursor.
+ * </p>
*
- * @return The text selection end if there is selection or -1.
+ * @return The text selection end, the cursor location if there is no selection, or -1 if
+ * there is no text selection and no cursor.
*/
public int getTextSelectionEnd() {
return mTextSelectionEnd;
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/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index df84970..7b6fa6d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -565,6 +565,12 @@
private Runnable mTouchModeReset;
/**
+ * Whether the most recent touch event stream resulted in a successful
+ * long-press action. This is reset on TOUCH_DOWN.
+ */
+ private boolean mHasPerformedLongPress;
+
+ /**
* This view is in transcript mode -- it shows the bottom of the list when the data
* changes
*/
@@ -3108,7 +3114,9 @@
handled = performLongPress(child, longPressPosition, longPressId);
}
}
+
if (handled) {
+ mHasPerformedLongPress = true;
mTouchMode = TOUCH_MODE_REST;
setPressed(false);
child.setPressed(false);
@@ -3811,6 +3819,7 @@
}
private void onTouchDown(MotionEvent ev) {
+ mHasPerformedLongPress = false;
mActivePointerId = ev.getPointerId(0);
if (mTouchMode == TOUCH_MODE_OVERFLING) {
@@ -3874,6 +3883,11 @@
}
private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
+ if (mHasPerformedLongPress) {
+ // Consume all move events following a successful long press.
+ return;
+ }
+
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
pointerIndex = 0;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 617d3dd..3a61fcd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2872,6 +2872,7 @@
protected PopupWindow mPopupWindow;
protected ViewGroup mContentView;
int mPositionX, mPositionY;
+ int mClippingLimitLeft, mClippingLimitRight;
protected abstract void createPopupWindow();
protected abstract void initContentView();
@@ -2939,8 +2940,9 @@
// Horizontal clipping
final DisplayMetrics displayMetrics = mTextView.getResources().getDisplayMetrics();
final int width = mContentView.getMeasuredWidth();
- positionX = Math.min(displayMetrics.widthPixels - width, positionX);
- positionX = Math.max(0, positionX);
+ positionX = Math.min(
+ displayMetrics.widthPixels - width + mClippingLimitRight, positionX);
+ positionX = Math.max(-mClippingLimitLeft, positionX);
if (isShowing()) {
mPopupWindow.update(positionX, positionY, -1, -1);
@@ -3118,6 +3120,8 @@
private TextView mAddToDictionaryButton;
private TextView mDeleteButton;
private SuggestionSpan mMisspelledSpan;
+ private int mContainerMarginWidth;
+ private int mContainerMarginTop;
private class CustomPopupWindow extends PopupWindow {
@Override
@@ -3155,10 +3159,20 @@
protected void initContentView() {
final LayoutInflater inflater = (LayoutInflater) mTextView.getContext().
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- final LinearLayout linearLayout = (LinearLayout) inflater.inflate(
+ final ViewGroup relativeLayout = (ViewGroup) inflater.inflate(
mTextView.mTextEditSuggestionContainerLayout, null);
- final ListView suggestionListView = (ListView) linearLayout.findViewById(
+ final LinearLayout suggestionWindowContainer =
+ (LinearLayout) relativeLayout.findViewById(
+ com.android.internal.R.id.suggestionWindowContainer);
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) suggestionWindowContainer.getLayoutParams();
+ mContainerMarginWidth = lp.leftMargin + lp.rightMargin;
+ mContainerMarginTop = lp.topMargin;
+ mClippingLimitLeft = lp.leftMargin;
+ mClippingLimitRight = lp.rightMargin;
+
+ final ListView suggestionListView = (ListView) relativeLayout.findViewById(
com.android.internal.R.id.suggestionContainer);
mSuggestionsAdapter = new SuggestionAdapter();
@@ -3171,9 +3185,9 @@
mSuggestionInfos[i] = new SuggestionInfo();
}
- mContentView = linearLayout;
+ mContentView = relativeLayout;
- mAddToDictionaryButton = (TextView) linearLayout.findViewById(
+ mAddToDictionaryButton = (TextView) relativeLayout.findViewById(
com.android.internal.R.id.addToDictionaryButton);
mAddToDictionaryButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -3197,7 +3211,7 @@
}
});
- mDeleteButton = (TextView) linearLayout.findViewById(
+ mDeleteButton = (TextView) relativeLayout.findViewById(
com.android.internal.R.id.deleteButton);
mDeleteButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -3306,6 +3320,8 @@
mDeleteButton.measure(horizontalMeasure, verticalMeasure);
width = Math.max(width, mDeleteButton.getMeasuredWidth());
+ width += mContainerMarginWidth;
+
// Enforce the width based on actual text widths
mContentView.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
@@ -3327,7 +3343,7 @@
@Override
protected int getVerticalLocalPosition(int line) {
- return mTextView.getLayout().getLineBottom(line);
+ return mTextView.getLayout().getLineBottom(line) - mContainerMarginTop;
}
@Override
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index 71c2c21..c7459d7 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.icu.util.ULocale;
+import android.icu.text.ListFormatter;
import android.util.LocaleList;
import java.text.Collator;
@@ -145,20 +146,16 @@
* @return the locale aware list of locale names
*/
public static String getDisplayLocaleList(LocaleList locales, Locale displayLocale) {
- final StringBuilder result = new StringBuilder();
-
final Locale dispLocale = displayLocale == null ? Locale.getDefault() : displayLocale;
+
int localeCount = locales.size();
+ final String[] localeNames = new String[localeCount];
for (int i = 0; i < localeCount; i++) {
- Locale locale = locales.get(i);
- result.append(LocaleHelper.getDisplayName(locale, dispLocale, false));
- // TODO: language aware list formatter. ICU has one.
- if (i < localeCount - 1) {
- result.append(", ");
- }
+ localeNames[i] = LocaleHelper.getDisplayName(locales.get(i), dispLocale, false);
}
- return result.toString();
+ ListFormatter lfn = ListFormatter.getInstance(dispLocale);
+ return lfn.format(localeNames);
}
/**
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index aada6e3..29190f9 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -32,6 +32,7 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -69,12 +70,11 @@
}
String dialogTitle;
- String dialogMessage;
+ String dialogMessage = null;
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
dialogTitle = getResources().getString(R.string.work_mode_off_title);
dialogMessage = getResources().getString(R.string.work_mode_off_message);
} else if (mReason == UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE) {
- PackageManager pm = getPackageManager();
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
@@ -91,12 +91,19 @@
}
dialogTitle = String.format(getResources().getString(R.string.suspended_package_title),
packageLabel);
- dialogMessage = dpm.getShortSupportMessageForUser(dpm.getProfileOwnerAsUser(mUserId),
- mUserId);
- if (dialogMessage == null) {
- dialogMessage = String.format(
- getResources().getString(R.string.suspended_package_message),
- dpm.getProfileOwnerNameAsUser(mUserId));
+ ComponentName profileOwner = dpm.getProfileOwnerAsUser(mUserId);
+ String profileOwnerName = null;
+ if (profileOwner != null) {
+ dialogMessage = dpm.getShortSupportMessageForUser(profileOwner, mUserId);
+ profileOwnerName = dpm.getProfileOwnerNameAsUser(mUserId);
+ }
+ // Fall back to standard message if profile owner hasn't set something specific.
+ if (TextUtils.isEmpty(dialogMessage)) {
+ if (TextUtils.isEmpty(profileOwnerName)) {
+ profileOwnerName = getResources().getString(R.string.unknownName);
+ }
+ dialogMessage = getResources().getString(R.string.suspended_package_message,
+ profileOwnerName);
}
} else {
Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index f81658e..3b8b7cb 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -86,6 +86,13 @@
Clog_e(TAG, message.toString(), e);
}
+ // Try to end profiling. If a profiler is running at this point, and we kill the
+ // process (below), the in-memory buffer will be lost. So try to stop, which will
+ // flush the buffer. (This makes method trace profiling useful to debug crashes.)
+ if (ActivityThread.currentActivityThread() != null) {
+ ActivityThread.currentActivityThread().stopProfiling();
+ }
+
// Bring up crash dialog, wait for it to be dismissed
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 976ef4b..480d806 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -920,14 +920,14 @@
mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
}
} else {
- if (hasOverflow()) {
- // overflow not open. Set closed state.
- final Size containerSize = mMainPanelSize;
- setSize(mContentContainer, containerSize);
- mMainPanel.setAlpha(1);
- mOverflowPanel.setAlpha(0);
- mOverflowButton.setImageDrawable(mOverflow);
+ // Overflow not open. Set closed state.
+ final Size containerSize = mMainPanelSize;
+ setSize(mContentContainer, containerSize);
+ mMainPanel.setAlpha(1);
+ mOverflowPanel.setAlpha(0);
+ mOverflowButton.setImageDrawable(mOverflow);
+ if (hasOverflow()) {
// Update x-coordinates depending on RTL state.
if (isRTL()) {
mContentContainer.setX(mMarginHorizontal); // align left
@@ -960,8 +960,11 @@
mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
}
} else {
- mContentContainer.setX(mMarginHorizontal);
- mContentContainer.setY(mMarginVertical);
+ // No overflow.
+ mContentContainer.setX(mMarginHorizontal); // align left
+ mContentContainer.setY(mMarginVertical); // align top
+ mMainPanel.setX(0); // align left
+ mMainPanel.setY(0); // align top
}
}
}
@@ -1092,6 +1095,7 @@
final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
mMainPanel.removeAllViews();
+ mMainPanel.setPaddingRelative(0, 0, 0, 0);
boolean isFirstItem = true;
while (!remainingMenuItems.isEmpty()) {
@@ -1302,7 +1306,6 @@
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final Drawable drawable = overflowButton.getDrawable();
if (mIsOverflowOpen) {
overflowButton.setImageDrawable(mToOverflow);
mToOverflow.start();
@@ -1599,6 +1602,8 @@
private static ViewGroup createContentContainer(Context context) {
ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
.inflate(R.layout.floating_popup_container, null);
+ contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
contentContainer.setTag(FLOATING_TOOLBAR_TAG);
return contentContainer;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3f468ac..ba456f9 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,7 +17,6 @@
package com.android.internal.widget;
import android.annotation.IntDef;
-import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
@@ -503,10 +502,9 @@
if (userHandle == UserHandle.USER_SYSTEM) {
// Set the encryption password to default.
updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ setCredentialRequiredToDecrypt(false);
}
- setCredentialRequiredToDecrypt(false);
-
getDevicePolicyManager().setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
@@ -1340,9 +1338,9 @@
}
public void setCredentialRequiredToDecrypt(boolean required) {
- if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
- Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
- return;
+ if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
+ throw new IllegalStateException(
+ "Only the system or primary user may call setCredentialRequiredForDecrypt()");
}
if (isDeviceEncryptionEnabled()){
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
new file mode 100644
index 0000000..b45fd06
--- /dev/null
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -0,0 +1,136 @@
+/*
+ * 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 com.android.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.RemoteViews;
+
+/**
+ * A TextView that can float around an image on the end.
+ *
+ * @hide
+ */
+@RemoteViews.RemoteView
+public class MediaNotificationView extends RelativeLayout {
+
+ private final int mMaxImageSize;
+ private final int mImageMarginBottom;
+ private final int mImageMinTopMargin;
+ private final int mNotificationContentMarginEnd;
+ private final int mNotificationContentImageMarginEnd;
+ private ImageView mRightIcon;
+ private View mActions;
+ private View mHeader;
+
+ public MediaNotificationView(Context context) {
+ this(context, null);
+ }
+
+ public MediaNotificationView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MediaNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int mode = MeasureSpec.getMode(widthMeasureSpec);
+ boolean hasIcon = mRightIcon.getVisibility() != GONE;
+ if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
+ measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
+ int size = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ size = size - mActions.getMeasuredWidth();
+ ViewGroup.MarginLayoutParams layoutParams =
+ (MarginLayoutParams) mRightIcon.getLayoutParams();
+ size -= layoutParams.getMarginEnd();
+ size = Math.min(size, mMaxImageSize);
+ size = Math.max(size, mRightIcon.getMinimumWidth());
+ layoutParams.width = size;
+ layoutParams.height = size;
+ // because we can't allign it to the bottom with a margin, we add a topmargin to it
+ layoutParams.topMargin = height - size - mImageMarginBottom;
+ // If the topMargin is high enough we can also remove the header constraint!
+ if (layoutParams.topMargin >= mImageMinTopMargin) {
+ resetHeaderIndention();
+ } else {
+ int paddingEnd = mNotificationContentImageMarginEnd;
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(size + layoutParams.getMarginEnd());
+ if (mHeader.getPaddingEnd() != paddingEnd) {
+ mHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
+ mHeader.getPaddingTop(),
+ isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
+ mHeader.getPaddingBottom());
+ mHeader.setLayoutParams(headerParams);
+ }
+ }
+ mRightIcon.setLayoutParams(layoutParams);
+ } else if (!hasIcon && mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
+ resetHeaderIndention();
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ private void resetHeaderIndention() {
+ if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(0);
+ mHeader.setPadding(
+ isLayoutRtl() ? mNotificationContentMarginEnd : mHeader.getPaddingLeft(),
+ mHeader.getPaddingTop(),
+ isLayoutRtl() ? mHeader.getPaddingLeft() : mNotificationContentMarginEnd,
+ mHeader.getPaddingBottom());
+ mHeader.setLayoutParams(headerParams);
+ }
+ }
+
+ public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mMaxImageSize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.media_notification_expanded_image_max_size);
+ mImageMarginBottom = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.media_notification_expanded_image_margin_bottom);
+ mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_top)
+ + getResources().getDisplayMetrics().density * 2);
+ mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
+ mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_image_margin_end);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mRightIcon = (ImageView) findViewById(com.android.internal.R.id.right_icon);
+ mActions = findViewById(com.android.internal.R.id.media_actions);
+ mHeader = findViewById(com.android.internal.R.id.notification_header);
+ }
+}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index b977e37..d25da78 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -54,6 +54,10 @@
};
static audio_attributes_fields_t javaAudioAttrFields;
static audio_record_fields_t javaAudioRecordFields;
+static struct {
+ jfieldID fieldFramePosition; // AudioTimestamp.framePosition
+ jfieldID fieldNanoTime; // AudioTimestamp.nanoTime
+} javaAudioTimestampFields;
struct audiorecord_callback_cookie {
jclass audioRecord_class;
@@ -678,7 +682,40 @@
}
}
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
+ jobject timestamp, jint timebase) {
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for getTimestamp()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ // TODO Enable.
+#if 0
+ // get the record timestamp
+ ExtendedTimestamp ts;
+ jint status = nativeToJavaStatus(lpRecorder->getExtendedTimestamp(&ts));
+
+ if (status == AUDIO_JAVA_SUCCESS) {
+ // set the data
+ int64_t position, time;
+
+ status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
+ if (status == AUDIO_JAVA_SUCCESS) {
+ env->SetLongField(
+ timestamp, javaAudioTimestampFields.fieldFramePosition, position);
+ env->SetLongField(
+ timestamp, javaAudioTimestampFields.fieldNanoTime, time);
+ }
+ }
+ return status;
+#else
+ return (jint)AUDIO_JAVA_INVALID_OPERATION;
+#endif
+}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -716,6 +753,8 @@
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
(void *)android_media_AudioRecord_disableDeviceCallback},
+ {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
+ (void *)android_media_AudioRecord_get_timestamp},
};
// field names found in android/media/AudioRecord.java
@@ -758,6 +797,13 @@
javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
+ // Get the RecordTimestamp class and fields
+ jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
+ javaAudioTimestampFields.fieldFramePosition =
+ GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
+ javaAudioTimestampFields.fieldNanoTime =
+ GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
+
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index e8ff186..aa78eff 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -16,17 +16,17 @@
-->
<!-- Layout for the expanded media notification -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.MediaNotificationView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
- android:layout_height="128dp"
+ android:layout_height="126dp"
android:background="#00000000"
android:tag="bigMediaNarrow"
>
<include layout="@layout/notification_template_header"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="48dp"
- android:layout_marginEnd="106dp"/>
+ android:layout_alignParentStart="true"/>
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
@@ -34,7 +34,7 @@
android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginBottom="@dimen/notification_content_margin_bottom"
- android:layout_marginEnd="24dp"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_toStartOf="@id/right_icon"
android:minHeight="@dimen/notification_min_content_height"
android:orientation="vertical"
@@ -57,12 +57,13 @@
</LinearLayout>
<ImageView android:id="@+id/right_icon"
- android:layout_width="96dp"
- android:layout_height="96dp"
+ android:layout_width="@dimen/media_notification_expanded_image_max_size"
+ android:layout_height="@dimen/media_notification_expanded_image_max_size"
+ android:minWidth="40dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
/>
-</RelativeLayout>
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 9fcd356..aea9b44 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -24,8 +24,7 @@
>
<include layout="@layout/notification_template_header"
android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:layout_marginEnd="106dp"/>
+ android:layout_height="48dp" />
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
@@ -34,7 +33,6 @@
android:orientation="horizontal"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginTop="@dimen/notification_content_margin_top"
- android:layout_marginEnd="72dp"
android:tag="media"
>
<LinearLayout
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index fe02d4e..17e93d0 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -14,32 +14,41 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="@drawable/text_edit_suggestions_window"
- android:dropDownSelector="@drawable/list_selector_background"
- android:divider="@null">
- <ListView
- android:id="@+id/suggestionContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:divider="?android:attr/dividerHorizontal">
- <!-- Suggestions will be added here. -->
- </ListView>
-
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/suggestionWindowContainer"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="middle">
- <TextView
- style="@android:style/Widget.Holo.SuggestionButton"
- android:id="@+id/addToDictionaryButton"
- android:text="@string/addToDictionary" />
- <TextView
- style="@android:style/Widget.Holo.SuggestionButton"
- android:id="@+id/deleteButton"
- android:text="@string/deleteText" />
+ android:elevation="2dp"
+ android:layout_margin="20dp"
+ android:background="@drawable/text_edit_suggestions_window"
+ android:dropDownSelector="@drawable/list_selector_background"
+ android:divider="@null">
+ <ListView
+ android:id="@+id/suggestionContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="?android:attr/dividerHorizontal">
+ <!-- Suggestions will be added here. -->
+ </ListView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle">
+ <TextView
+ style="@android:style/Widget.Holo.SuggestionButton"
+ android:id="@+id/addToDictionaryButton"
+ android:text="@string/addToDictionary" />
+ <TextView
+ style="@android:style/Widget.Holo.SuggestionButton"
+ android:id="@+id/deleteButton"
+ android:text="@string/deleteText" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 62e315b4..7826803 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -16,29 +16,38 @@
<!-- Background of the popup window is the same as the one of the floating toolbar.
Use floating toolbar background style. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
- android:divider="?android:attr/listDivider"
- android:showDividers="middle" >
- <ListView
- android:id="@+id/suggestionContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dip"
- android:paddingBottom="0dip"
- android:divider="@null" />
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/suggestionWindowContainer"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- style="@android:style/Widget.Material.SuggestionButton"
- android:id="@+id/addToDictionaryButton"
- android:text="@string/addToDictionary" />
- <TextView
- style="@android:style/Widget.Material.SuggestionButton"
- android:id="@+id/deleteButton"
- android:text="@string/deleteText" />
+ android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+ android:elevation="2dp"
+ android:layout_margin="20dp"
+ android:orientation="vertical"
+ android:divider="?android:attr/listDivider"
+ android:showDividers="middle">
+ <ListView
+ android:id="@+id/suggestionContainer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="0dp"
+ android:divider="@null" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ style="@android:style/Widget.Material.SuggestionButton"
+ android:id="@+id/addToDictionaryButton"
+ android:text="@string/addToDictionary" />
+ <TextView
+ style="@android:style/Widget.Material.SuggestionButton"
+ android:id="@+id/deleteButton"
+ android:text="@string/deleteText" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index f92e7f0..7c6f338 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -146,6 +146,9 @@
<!-- The margin on the end of the content view with a picture.-->
<dimen name="notification_content_picture_margin">56dp</dimen>
+ <!-- The margin on the end of the content view with a picture in the compact media.-->
+ <dimen name="notification_content_picture_margin_media">72dp</dimen>
+
<!-- height of the content margin to accomodate for the header -->
<dimen name="notification_content_margin_top">30dp</dimen>
@@ -169,6 +172,15 @@
<!-- The minimum height of the content if there are at least two lines or a picture-->
<dimen name="notification_min_content_height">41dp</dimen>
+ <!-- The maximum size of the image in the expanded media notification -->
+ <dimen name="media_notification_expanded_image_max_size">94dp</dimen>
+
+ <!-- The maximum size of the image in the expanded media notification -->
+ <dimen name="media_notification_expanded_image_margin_bottom">16dp</dimen>
+
+ <!-- The margin of the content to an image-->
+ <dimen name="notification_content_image_margin_end">8dp</dimen>
+
<!-- Preferred width of the search view. -->
<dimen name="search_view_preferred_width">320dip</dimen>
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/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index aa44d7c..74ca8a5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2388,6 +2388,7 @@
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<!-- EditText suggestion popup. -->
+ <java-symbol type="id" name="suggestionWindowContainer" />
<java-symbol type="id" name="suggestionContainer" />
<java-symbol type="id" name="addToDictionaryButton" />
<java-symbol type="id" name="deleteButton" />
@@ -2503,6 +2504,11 @@
<java-symbol type="string" name="new_sms_notification_title" />
<java-symbol type="string" name="new_sms_notification_content" />
+ <java-symbol type="dimen" name="media_notification_expanded_image_max_size" />
+ <java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
+ <java-symbol type="dimen" name="notification_content_image_margin_end" />
+ <java-symbol type="dimen" name="notification_content_picture_margin_media" />
+
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
<!-- Encryption notification while accounts are locked by credential encryption -->
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 4d4acb9..1cf15ac 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -201,7 +201,6 @@
needsFill = true;
} else if (mFillColor != SK_ColorTRANSPARENT) {
mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
- outCanvas->drawPath(renderPath, mPaint);
needsFill = true;
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 7c21893..800b914 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -826,6 +826,33 @@
}
/**
+ * Poll for an {@link AudioTimestamp} on demand.
+ * <p>
+ * The AudioTimestamp reflects the frame delivery information at
+ * the earliest point available in the capture pipeline.
+ * <p>
+ * Calling {@link #startRecording()} following a {@link #stop()} will reset
+ * the frame count to 0.
+ *
+ * @param timestamp a reference to a non-null AudioTimestamp instance.
+ * @param timebase one of
+ * {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
+ * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}.
+ * @return {@link #SUCCESS} if a timestamp is available,
+ * or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
+ */
+ public int getTimestamp(@NonNull AudioTimestamp timestamp,
+ @AudioTimestamp.Timebase int timebase)
+ {
+ if (timestamp == null ||
+ (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
+ && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
+ throw new IllegalArgumentException();
+ }
+ return native_get_timestamp(timestamp, timebase);
+ }
+
+ /**
* Returns the minimum buffer size required for the successful creation of an AudioRecord
* object, in byte units.
* Note that this size doesn't guarantee a smooth recording under load, and higher values
@@ -1709,6 +1736,9 @@
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
+ private native final int native_get_timestamp(@NonNull AudioTimestamp timestamp,
+ @AudioTimestamp.Timebase int timebase);
+
//---------------------------------------------------------
// Utility methods
//------------------
diff --git a/media/java/android/media/AudioTimestamp.java b/media/java/android/media/AudioTimestamp.java
index 965ba85..be8ca15 100644
--- a/media/java/android/media/AudioTimestamp.java
+++ b/media/java/android/media/AudioTimestamp.java
@@ -16,29 +16,74 @@
package android.media;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
+
/**
* Structure that groups a position in frame units relative to an assumed audio stream,
- * together with the estimated time when that frame was presented or is committed to be
- * presented.
- * In the case of audio output, "present" means that audio produced on device
- * is detectable by an external observer off device.
+ * together with the estimated time when that frame enters or leaves the audio
+ * processing pipeline on that device. This can be used to coordinate events
+ * and interactions with the external environment.
+ * <p>
* The time is based on the implementation's best effort, using whatever knowledge
* is available to the system, but cannot account for any delay unknown to the implementation.
*
- * @see AudioTrack#getTimestamp
+ * @see AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)
+ * @see AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)
*/
public final class AudioTimestamp
{
/**
+ * Clock monotonic or its equivalent on the system,
+ * in the same units and timebase as {@link java.lang.System#nanoTime}.
+ */
+ public static final int TIMEBASE_MONOTONIC = 0;
+
+ /**
+ * Clock monotonic including suspend time or its equivalent on the system,
+ * in the same units and timebase as {@link android.os.SystemClock#elapsedRealtimeNanos}.
+ */
+ public static final int TIMEBASE_BOOTTIME = 1;
+
+ /** @hide */
+ @IntDef({
+ TIMEBASE_MONOTONIC,
+ TIMEBASE_BOOTTIME,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Timebase {}
+
+ /**
* Position in frames relative to start of an assumed audio stream.
- * The low-order 32 bits of position is in wrapping frame units similar to
- * {@link AudioTrack#getPlaybackHeadPosition}.
+ * <p>
+ * When obtained through
+ * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)},
+ * all 64 bits of position are valid.
+ * <p>
+ * When obtained through
+ * {@link AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)},
+ * the low-order 32 bits of position is in wrapping frame units similar to
+ * {@link AudioTrack#getPlaybackHeadPosition AudioTrack.getPlaybackHeadPosition()}.
*/
public long framePosition;
/**
- * The estimated time when frame was presented or is committed to be presented,
- * in the same units and timebase as {@link java.lang.System#nanoTime}.
+ * Time associated with the frame in the audio pipeline.
+ * <p>
+ * When obtained through
+ * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)},
+ * this is the estimated time in nanoseconds when the frame referred to by
+ * {@link #framePosition} was captured. The timebase is either
+ * {@link #TIMEBASE_MONOTONIC} or {@link #TIMEBASE_BOOTTIME}, depending
+ * on the timebase parameter used in
+ * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)}.
+ * <p>
+ * When obtained through
+ * {@link AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)},
+ * this is the estimated time when the frame was presented or is committed to be presented,
+ * with a timebase of {@link #TIMEBASE_MONOTONIC}.
*/
public long nanoTime;
}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 869512d..93e6dac 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -473,8 +473,9 @@
// the service will be told when we connect.
if (mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: In order not to break the behavior of the support library, call
- // addSubscription instead of addSubscriptionWithOptions when the options are null.
+ // NOTE: Do not call addSubscriptionWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects addSubscription will
+ // be called when options are null.
if (options == null) {
mServiceBinder.addSubscription(parentId, mServiceCallbacks);
} else {
@@ -500,9 +501,9 @@
// Tell the service if necessary.
if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: In order not to break the behavior of the support library, call
- // removeSubscription instead of removeSubscriptionWithOptions when the options
- // are null.
+ // NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects removeSubscription will
+ // be called when options are null.
if (options == null) {
mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
} else {
@@ -572,9 +573,9 @@
Subscription sub = subscriptionEntry.getValue();
for (Bundle options : sub.getOptionsList()) {
try {
- // NOTE: In order not to break the behavior of the support library,
- // call addSubscription instead of addSubscriptionWithOptions when
- // the options are null.
+ // NOTE: Do not call addSubscriptionWithOptions when options are null.
+ // Otherwise, it will break the action of support library which expects
+ // addSubscription will be called when options are null.
if (options == null) {
mServiceBinder.addSubscription(id, mServiceCallbacks);
} else {
@@ -1034,7 +1035,7 @@
* are the initial data as requested.
*/
@Override
- public void onConnect(final String root, final MediaSession.Token session,
+ public void onConnect(String root, MediaSession.Token session,
final Bundle extras) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
@@ -1054,7 +1055,12 @@
}
@Override
- public void onLoadChildren(final String parentId, final ParceledListSlice list,
+ public void onLoadChildren(String parentId, ParceledListSlice list) {
+ onLoadChildrenWithOptions(parentId, list, null);
+ }
+
+ @Override
+ public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list,
final Bundle options) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
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..4fdc102 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -24,9 +24,7 @@
* @hide
*/
oneway interface ITvInputServiceCallback {
- 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);
+ void addHardwareInput(in int deviceId, in TvInputInfo inputInfo);
+ void addHdmiInput(in int id, in TvInputInfo inputInfo);
+ void removeHardwareInput(in String inputId);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f1de8fd..1cd1958 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -719,19 +719,16 @@
* the media on which a newer version of the package exists becomes available/unavailable.
*
* @param inputId The ID of the TV input.
- * @hide
*/
- @SystemApi
public void onInputUpdated(String inputId) {
}
/**
- * 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 +781,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 +1086,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 +1140,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..d48b2c8 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -150,25 +150,25 @@
@Override
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_INPUT,
deviceInfo).sendToTarget();
}
@Override
public void notifyHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT,
deviceInfo).sendToTarget();
}
};
@@ -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) {
@@ -525,7 +525,7 @@
public void notifyVideoUnavailable(final int reason) {
if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
|| reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
- throw new IllegalArgumentException("Unknown reason: " + reason);
+ Log.e(TAG, "notifyVideoUnavailable - unknown reason: " + reason);
}
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -1934,55 +1934,42 @@
private static final int DO_CREATE_SESSION = 1;
private static final int DO_NOTIFY_SESSION_CREATED = 2;
private static final int DO_CREATE_RECORDING_SESSION = 3;
- private static final int DO_ADD_HARDWARE_TV_INPUT = 4;
- 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 static final int DO_ADD_HARDWARE_INPUT = 4;
+ private static final int DO_REMOVE_HARDWARE_INPUT = 5;
+ private static final int DO_ADD_HDMI_INPUT = 6;
+ private static final int DO_REMOVE_HDMI_INPUT = 7;
- private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
+ private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHardwareInput(deviceId, inputInfo);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastAddHardwareTvInput", e);
+ Log.e(TAG, "error in broadcastAddHardwareInput", e);
}
}
mCallbacks.finishBroadcast();
}
- private void broadcastAddHdmiTvInput(int id, TvInputInfo inputInfo) {
+ private void broadcastAddHdmiInput(int id, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHdmiTvInput(id, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHdmiInput(id, inputInfo);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastAddHdmiTvInput", e);
+ Log.e(TAG, "error in broadcastAddHdmiInput", e);
}
}
mCallbacks.finishBroadcast();
}
- private void broadcastRemoveTvInput(String inputId) {
+ private void broadcastRemoveHardwareInput(String inputId) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).removeTvInput(inputId);
+ mCallbacks.getBroadcastItem(i).removeHardwareInput(inputId);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastRemoveTvInput", e);
- }
- }
- 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);
+ Log.e(TAG, "error in broadcastRemoveHardwareInput", e);
}
}
mCallbacks.finishBroadcast();
@@ -2088,48 +2075,38 @@
recordingSessionImpl.initialize(cb);
return;
}
- case DO_ADD_HARDWARE_TV_INPUT: {
+ case DO_ADD_HARDWARE_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
TvInputInfo inputInfo = onHardwareAdded(hardwareInfo);
if (inputInfo != null) {
- broadcastAddHardwareTvInput(hardwareInfo.getDeviceId(), inputInfo);
+ broadcastAddHardwareInput(hardwareInfo.getDeviceId(), inputInfo);
}
return;
}
- case DO_REMOVE_HARDWARE_TV_INPUT: {
+ case DO_REMOVE_HARDWARE_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
String inputId = onHardwareRemoved(hardwareInfo);
if (inputId != null) {
- broadcastRemoveTvInput(inputId);
+ broadcastRemoveHardwareInput(inputId);
}
return;
}
- case DO_ADD_HDMI_TV_INPUT: {
+ case DO_ADD_HDMI_INPUT: {
HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
TvInputInfo inputInfo = onHdmiDeviceAdded(deviceInfo);
if (inputInfo != null) {
- broadcastAddHdmiTvInput(deviceInfo.getId(), inputInfo);
+ broadcastAddHdmiInput(deviceInfo.getId(), inputInfo);
}
return;
}
- case DO_REMOVE_HDMI_TV_INPUT: {
+ case DO_REMOVE_HDMI_INPUT: {
HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
String inputId = onHdmiDeviceRemoved(deviceInfo);
if (inputId != null) {
- broadcastRemoveTvInput(inputId);
+ broadcastRemoveHardwareInput(inputId);
}
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/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 865e000..73f1e32 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -184,7 +184,7 @@
* Callback used to receive various status updates on the
* {@link android.media.tv.TvInputService.RecordingSession}
*/
- public class RecordingCallback {
+ public abstract static class RecordingCallback {
/**
* This is called when a recording session initiated by a call to
* {@link #connect(String, Uri)} has been established.
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index fe7ebfa..6ca5ac5 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -16,7 +16,7 @@
oneway interface IMediaBrowserService {
// Warning: DO NOT CHANGE the methods signature and order of methods.
- // The change of the order or the method signatures could break the support library.
+ // A change of the order or the method signatures could break the support library.
void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
void disconnect(IMediaBrowserServiceCallbacks callbacks);
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
index dadb025..e6b0e8c 100644
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -13,6 +13,10 @@
* @hide
*/
oneway interface IMediaBrowserServiceCallbacks {
+
+ // Warning: DO NOT CHANGE the methods signature and order of methods.
+ // A change of the order or the method signatures could break the support library.
+
/**
* Invoked when the connected has been established.
* @param root The root media id for browsing.
@@ -22,5 +26,6 @@
*/
void onConnect(String root, in MediaSession.Token session, in Bundle extras);
void onConnectFailed();
- void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options);
+ void onLoadChildren(String mediaId, in ParceledListSlice list);
+ void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options);
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 6cf90d5..299b770 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -589,7 +589,14 @@
final ParceledListSlice<MediaBrowser.MediaItem> pls =
filteredList == null ? null : new ParceledListSlice<>(filteredList);
try {
- connection.callbacks.onLoadChildren(parentId, pls, options);
+ // NOTE: Do not call onLoadChildrenWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects onLoadChildren will
+ // be called when options are null.
+ if (options == null) {
+ connection.callbacks.onLoadChildren(parentId, pls);
+ } else {
+ connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
+ }
} catch (RemoteException ex) {
// The other side is in the process of crashing.
Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 025133f..3b892cb 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -150,4 +150,8 @@
mJavaObjStatus = UNKNOWN_ERROR;
}
+uint32_t JMediaDataSource::getFlags() {
+ return 0;
+}
+
} // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 2bc237e..34624eb 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -45,6 +45,7 @@
virtual ssize_t readAt(off64_t offset, size_t size);
virtual status_t getSize(off64_t* size);
virtual void close();
+ virtual uint32_t getFlags();
private:
// Protect all member variables with mLock because this object will be
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index c3452d5..fa9ff01 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -54,8 +54,7 @@
android:name=".LauncherActivity"
android:theme="@android:style/Theme.NoDisplay"
android:icon="@drawable/ic_files_app"
- android:label="@string/files_label"
- android:enabled="@bool/productivity_device">
+ android:label="@string/files_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ff28e15..e8d8c8e 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -18,7 +18,6 @@
<!-- Allow Advanced Devices default value to be customised -->
<bool name="config_defaultAdvancedDevices">false</bool>
- <bool name="productivity_device">true</bool>
<!-- Intentionally unset. Vendors should set this in an overlay. -->
<string name="trusted_quick_viewer_package"></string>
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index d235b30..ea7054f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -104,7 +104,6 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mProductivityDevice = getResources().getBoolean(R.bool.productivity_device);
mState = (icicle != null)
? icicle.<State>getParcelable(EXTRA_STATE)
: buildState();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 393fdcd..f51f689 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -16,12 +16,11 @@
package com.android.documentsui;
+import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkState;
-import static com.android.documentsui.OperationDialogFragment.DialogType;
-import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
import android.app.Activity;
import android.app.FragmentManager;
@@ -45,6 +44,7 @@
import android.widget.Spinner;
import android.widget.Toolbar;
+import com.android.documentsui.OperationDialogFragment.DialogType;
import com.android.documentsui.RecentsProvider.ResumeColumns;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.model.DocumentInfo;
@@ -256,9 +256,6 @@
pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
- newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- newWindow.setVisible(mProductivityDevice);
-
Menus.disableHiddenItems(menu, pasteFromCb);
return true;
}
@@ -287,6 +284,14 @@
Metrics.logMultiWindow(this);
Intent intent = LauncherActivity.createLaunchIntent(this);
intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
+
+ // With new multi-window mode we have to pick how we are launched.
+ // By default we'd be launched in-place above the existing app.
+ // By setting launch-to-side ActivityManager will open us to side.
+ if (inMultiWindowMode()) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE);
+ }
+
startActivity(intent);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
index b3d0cf3..7930c28 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
@@ -74,6 +74,9 @@
private void startTask() {
Intent intent = createLaunchIntent(this);
+
+ // Forward any flags from the original intent.
+ intent.setFlags(getIntent().getFlags());
if (DEBUG) Log.d(TAG, "Starting new task > " + intent.getData());
startActivity(intent);
}
@@ -84,7 +87,7 @@
startActivity(intent);
}
- static Intent createLaunchIntent(Context context) {
+ static final Intent createLaunchIntent(Context context) {
Intent intent = new Intent(context, FilesActivity.class);
intent.setData(buildLaunchUri());
return intent;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 112914e..959fac6 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -165,22 +165,27 @@
cursor.close();
}
- long capacityBytes = 0;
- long availableBytes = 0;
- int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
- int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
- while (storageCursor.moveToNext()) {
- // If requested columnNames does not include COLUMN_XXX_BYTES, we don't
- // calculate corresponding values.
- if (capacityIndex != -1) {
- capacityBytes += cursor.getLong(capacityIndex);
+ if (storageCursor.getCount() != 0) {
+ long capacityBytes = 0;
+ long availableBytes = 0;
+ int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
+ int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
+ while (storageCursor.moveToNext()) {
+ // If requested columnNames does not include COLUMN_XXX_BYTES, we
+ // don't calculate corresponding values.
+ if (capacityIndex != -1) {
+ capacityBytes += cursor.getLong(capacityIndex);
+ }
+ if (availableIndex != -1) {
+ availableBytes += cursor.getLong(availableIndex);
+ }
}
- if (availableIndex != -1) {
- availableBytes += cursor.getLong(availableIndex);
- }
+ values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
+ values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
+ } else {
+ values.putNull(Root.COLUMN_CAPACITY_BYTES);
+ values.putNull(Root.COLUMN_AVAILABLE_BYTES);
}
- values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
- values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
}
} finally {
storageCursor.close();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 97ea717..8075999 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -899,4 +899,24 @@
mDatabase.getMapper().stopAddingDocuments(null);
assertEquals("1", mDatabase.getDocumentIdForDevice(100));
}
+
+ public void testGetClosedDevice() {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", /* opened is */ false , new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ final String[] columns = new String [] {
+ DocumentsContract.Root.COLUMN_ROOT_ID,
+ DocumentsContract.Root.COLUMN_TITLE,
+ DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
+ };
+ try (final Cursor cursor = mDatabase.queryRoots(columns)) {
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(1, cursor.getLong(0));
+ assertEquals("Device", cursor.getString(1));
+ assertTrue(cursor.isNull(2));
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index ad567d3..210682f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.graphics.Color;
@@ -227,6 +228,26 @@
}
/**
+ * Check if an application is suspended.
+ *
+ * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+ * or {@code null} if the application is not suspended.
+ */
+ public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
+ int userId) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ try {
+ ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
+ if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
+ return getProfileOrDeviceOwnerOnCallingUser(context);
+ }
+ } catch (RemoteException e) {
+ // Nothing to do
+ }
+ return null;
+ }
+
+ /**
* Check if account management for a specific type of account is disabled by admin.
* Only a profile or device owner can disable account management. So, we check if account
* management is disabled and return profile or device owner on the calling user.
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index f1beb10..5c8849d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -29,7 +29,6 @@
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -56,6 +55,7 @@
private final UserManager mUserManager;
private final UserHandle mUser;
private final boolean mRestrictedProfile;
+ private boolean mLeanback;
HashMap<String,Boolean> mSelectedPackages = new HashMap<>();
private List<SelectableAppInfo> mVisibleApps;
@@ -77,6 +77,10 @@
return mSelectedPackages.get(packageName);
}
+ public void setLeanback(boolean isLeanback) {
+ mLeanback = isLeanback;
+ }
+
public List<SelectableAppInfo> getVisibleApps() {
return mVisibleApps;
}
@@ -155,7 +159,11 @@
// Add launchers
Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
- launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ if (mLeanback) {
+ launcherIntent.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+ } else {
+ launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ }
addSystemApps(mVisibleApps, launcherIntent, excludePackages);
// Add widgets
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index e4d0fec..88313bb 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -12,6 +12,7 @@
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
+ android-support-v17-leanback \
framework-protos
LOCAL_JAVA_LIBRARIES := telephony-common
@@ -30,10 +31,12 @@
frameworks/support/v7/preference/res \
frameworks/support/v14/preference/res \
frameworks/support/v7/appcompat/res \
- frameworks/support/v7/recyclerview/res
+ frameworks/support/v7/recyclerview/res \
+ frameworks/support/v17/leanback/res
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat
+ --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat \
+ --extra-packages android.support.v17.leanback
ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 21abb90..2713fb5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -236,6 +236,20 @@
</intent-filter>
</activity>
+ <activity android:name=".recents.tv.RecentsTvActivity"
+ android:label="@string/accessibility_desc_recent_apps"
+ android:exported="false"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
+ android:stateNotNeeded="true"
+ android:resumeWhilePausing="true"
+ android:screenOrientation="behind"
+ android:theme="@style/RecentsTheme.Wallpaper">
+ <intent-filter>
+ <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+ </intent-filter>
+ </activity>
+
<!-- Callback for dismissing screenshot notification after a share target is picked -->
<receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
android:process=":screenshot"
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/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
new file mode 100644
index 0000000..b4543bd
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+<com.android.systemui.recents.tv.views.RecentsTvView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false" >
+
+ <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
+ android:id="@+id/task_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:descendantFocusability="beforeDescendants"
+ android:gravity="center"
+ android:paddingStart="@dimen/recents_tv_grid_row_padding"
+ android:paddingEnd="@dimen/recents_tv_grid_row_padding"
+ android:focusable="true"/>
+
+</com.android.systemui.recents.tv.views.RecentsTvView>
+
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_task_card_view.xml
new file mode 100644
index 0000000..fa1daad
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_card_view.xml
@@ -0,0 +1,77 @@
+<?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.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:layout_gravity="center"
+ android:layout_centerInParent="true">
+
+ <RelativeLayout
+ android:layout_width="@dimen/recents_tv_card_width"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_gravity="center">
+ <ImageView
+ android:id="@+id/card_view_thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/recents_tv_card_height"
+ android:scaleType="centerCrop"
+ android:gravity="center"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"/>
+
+ <RelativeLayout
+ android:id="@+id/card_info_field"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/card_view_thumbnail"
+ android:background="@color/recents_tv_card_background_color" >
+ <TextView
+ android:id="@+id/card_title_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="false"
+ android:includeFontPadding="true"
+ android:minLines="1"
+ android:maxLines="2"
+ android:textColor="@color/recents_tv_card_title_text_color"
+ android:ellipsize="end" />
+ <TextView
+ android:id="@+id/card_content_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/card_title_text"
+ android:includeFontPadding="true"
+ android:minLines="1"
+ android:maxLines="2"
+ android:textColor="@color/recents_tv_card_content_text_color"
+ android:ellipsize="end" />
+ <ImageView
+ android:id="@+id/card_extra_badge"
+ android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+ android:scaleType="fitCenter"
+ android:background="@android:color/transparent"
+ android:contentDescription="@null"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"/>
+ </RelativeLayout>
+ </RelativeLayout>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 955efb5..19bc755 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -28,9 +28,6 @@
<declare-styleable name="NotificationLinearLayout">
<attr name="insetLeft" format="dimension" />
</declare-styleable>
- <declare-styleable name="NotificationRowLayout">
- <attr name="rowHeight" format="dimension" />
- </declare-styleable>
<declare-styleable name="RecentsPanelView">
<attr name="recentItemLayout" format="reference" />
</declare-styleable>
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/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
new file mode 100644
index 0000000..6f4c983
--- /dev/null
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 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.
+ */
+-->
+<resources>
+ <color name="recents_tv_card_background_color">#FF37474F</color>
+ <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
+ <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
+ <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6df31ff..ebe0d97 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,7 +103,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast
+ wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast,work
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8b0350a..32d09e8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -606,5 +606,4 @@
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
-
</resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
new file mode 100644
index 0000000..77605bd
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 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.
+ */
+-->
+<resources>
+ <!-- Dimens for recents card in the recents view on tv -->
+ <dimen name="recents_tv_card_width">150dip</dimen>
+ <dimen name="recents_tv_card_height">85dip</dimen>
+ <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+
+ <!-- Padding for grid view in recents view on tv -->
+ <dimen name="recents_tv_grid_row_padding">56dip</dimen>
+ <dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
+ <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
+ <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+
+ <!-- Values for focus animation -->
+ <dimen name="recents_tv_unselected_item_z">6dp</dimen>
+ <dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
new file mode 100644
index 0000000..bfd8f8b
--- /dev/null
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<resources>
+ <integer name="item_scale_anim_duration">150</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
new file mode 100644
index 0000000..45cdc07
--- /dev/null
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <item format="float" type="raw" name="unselected_scale">1.0</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 38ae345..a0dbad4 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -22,12 +22,19 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
-import android.graphics.*;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
+
import com.android.systemui.statusbar.policy.BatteryController;
public class BatteryMeterDrawable extends Drawable implements DemoMode,
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index b4f63eb..0bf81e9 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
+
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
index fc98ec4..f8ce1d3 100644
--- a/packages/SystemUI/src/com/android/systemui/DejankUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
@@ -18,7 +18,6 @@
import android.os.Handler;
import android.os.Looper;
-import android.os.StrictMode;
import android.view.Choreographer;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
index 14392b4..5e96379 100644
--- a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
@@ -22,7 +22,14 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.*;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index ec19e5a..9a64a41 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -16,8 +16,6 @@
package com.android.systemui;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-
import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.content.BroadcastReceiver;
@@ -34,6 +32,8 @@
import android.util.Log;
import android.view.WindowManagerGlobal;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
/**
* Manages notification when a guest session is resumed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 5a6f3c9..1306284 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -17,6 +17,7 @@
package com.android.systemui;
import static android.opengl.GLES20.*;
+
import static javax.microedition.khronos.egl.EGL10.*;
import android.app.ActivityManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
rename to packages/SystemUI/src/com/android/systemui/Interpolators.java
index 5979468..cd6dce0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -14,9 +14,10 @@
* limitations under the License
*/
-package com.android.systemui.statusbar;
+package com.android.systemui;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
@@ -32,4 +33,5 @@
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
public static final Interpolator LINEAR = new LinearInterpolator();
public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
+ public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6b74652..33b43fe 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -32,7 +32,6 @@
import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.statusbar.Interpolators;
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index 25f8bb0..2c96e31 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -25,8 +25,6 @@
import android.graphics.Paint;
import android.view.View;
-import com.android.systemui.statusbar.Interpolators;
-
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index 0e28002..faaad2b 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -23,9 +23,9 @@
import java.util.ArrayList;
import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
/**
* Collects touch, sensor and phone events and converts the data to
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index 92cd027..5878219 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -33,8 +33,8 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
/**
* Visually discloses that contextual data was provided to an assistant.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
index 34770c4..f78436a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
@@ -22,8 +22,8 @@
import android.view.View;
import android.widget.FrameLayout;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class AssistOrbContainer extends FrameLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
index 2d933f6..abcf27d 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
@@ -32,8 +32,8 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class AssistOrbView extends FrameLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index a6ebc0b..dba731a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -18,8 +18,6 @@
import android.view.MotionEvent;
-import java.lang.Math;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 27d4c0e..7ddbdf0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.SensorEvent;
-import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
@@ -35,6 +34,10 @@
public class HumanInteractionClassifier extends Classifier {
private static final String HIC_ENABLE = "HIC_enable";
private static final float FINGER_DISTANCE = 0.1f;
+
+ /** Default value for the HIC_ENABLE setting: 1 - enabled, 0 - disabled */
+ private static final int HIC_ENABLE_DEFAULT = 1;
+
private static HumanInteractionClassifier sInstance = null;
private final Handler mHandler = new Handler();
@@ -101,9 +104,9 @@
}
private void updateConfiguration() {
- mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
+ mEnableClassifier = 0 != Settings.Global.getInt(
mContext.getContentResolver(),
- HIC_ENABLE, 0);
+ HIC_ENABLE, HIC_ENABLE_DEFAULT);
}
public void setType(int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index d544a3d..d58274d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -18,8 +18,6 @@
import android.view.MotionEvent;
-import java.lang.Math;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/egg/MLand.java b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
index b84777b..0fb4432 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/MLand.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
@@ -48,12 +48,11 @@
import android.widget.ImageView;
import android.widget.TextView;
-import java.util.ArrayList;
-
import com.android.internal.logging.MetricsLogger;
-
import com.android.systemui.R;
+import java.util.ArrayList;
+
// It's like LLand, but "M"ultiplayer.
public class MLand extends FrameLayout {
public static final String TAG = "MLand";
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
index 64f3e13f..5deea9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
@@ -16,11 +16,9 @@
package com.android.systemui.keyboard;
-import android.app.AlertDialog;
import android.content.Context;
import android.view.WindowManager;
-import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
public class BluetoothDialog extends SystemUIDialog {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 481b9180..ea7270d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -16,10 +16,8 @@
package com.android.systemui.keyboard;
-import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
@@ -29,7 +27,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.content.res.Configuration;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -42,7 +39,6 @@
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Slog;
-import android.view.WindowManager;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -58,7 +54,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Set;
public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index adc9b36..b2a80f4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -23,24 +23,23 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
-import android.media.projection.MediaProjectionManager;
-import android.media.projection.IMediaProjectionManager;
import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.BidiFormatter;
-import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.Log;
-import android.util.TypedValue;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
+
import com.android.systemui.R;
public class MediaProjectionPermissionActivity extends Activity
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index b3c0783..f201165 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -16,11 +16,6 @@
package com.android.systemui.net;
-import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
-import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
-import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -37,6 +32,11 @@
import com.android.systemui.R;
+import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
+import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
+import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+
/**
* Notify user that a {@link NetworkTemplate} is over its
* {@link NetworkPolicy#limitBytes}, giving them the choice of acknowledging or
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 6bc8b50..d723367 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,6 +6,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
index 699273a..a1c2577 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -16,8 +16,6 @@
package com.android.systemui.qs;
-import com.android.systemui.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -26,6 +24,8 @@
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import com.android.systemui.R;
+
import java.lang.ref.WeakReference;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 7651ae8..ed90904 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+
import com.android.systemui.R;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 789e72e..35000d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -23,7 +24,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -271,7 +271,7 @@
protected void checkIfRestrictionEnforced(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
- userRestriction, UserHandle.myUserId());
+ userRestriction, ActivityManager.getCurrentUser());
if (admin != null) {
state.disabledByPolicy = true;
state.enforcedAdmin = admin;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 68461f5..1a854c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -24,6 +24,7 @@
import android.os.Message;
import android.view.View;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
public class QSTileBaseView extends LinearLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 664ca39..0d5d115 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index b391c1e..753efb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 59a394f..f7e2338 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -5,6 +5,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanel.TileRecord;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index eab4dca..02cb0cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -27,6 +27,7 @@
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
index 8f0d194..98c7be4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import com.android.systemui.qs.PagedTileLayout;
import com.android.systemui.qs.PagedTileLayout.TilePage;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index cc4ce70..a6c7fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -37,6 +37,7 @@
import android.widget.ListView;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTile.Host.Callback;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 3748a30..a4d7e93 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -37,6 +37,7 @@
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.Icon;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 4977d80..c4436f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.qs.external;
+import libcore.util.Objects;
+
import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -35,7 +37,6 @@
import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
-import libcore.util.Objects;
import java.util.Set;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 44d8776..04391fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -33,6 +33,7 @@
import android.service.quicksettings.TileService;
import android.util.ArrayMap;
import android.util.Log;
+
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.StatusBarIconController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index fd8857d..64b3a6c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -25,6 +25,7 @@
import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.BatteryInfo;
import com.android.systemui.BatteryMeterDrawable;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 6a07a07..dbb7423 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,10 @@
@Override
protected void handleClick() {
+ if (!mController.canConfigBluetooth()) {
+ mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+ return;
+ }
if (!mState.value) {
mState.value = true;
mController.setBluetoothEnabled(true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index 2be43c0..bad4e79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 1f9f1c4..f99a3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -29,13 +29,11 @@
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
-import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.SysUIToast;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.ZenModePanel;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index db86047..2f37943 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -66,6 +68,8 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
+ state.disabledByPolicy = mController.isTetheringAllowed();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
if (arg instanceof Boolean) {
state.value = (boolean) arg;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 724659c..8328897 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -85,6 +87,8 @@
// bug is fixed, this should be reverted to only hiding it on secure lock screens:
// state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
state.value = locationEnabled;
+ state.disabledByPolicy = mController.isUserLocationRestricted();
+ checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
if (locationEnabled) {
state.icon = mEnable;
state.label = mContext.getString(R.string.quick_settings_location_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 167c611..33befd0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -16,11 +16,6 @@
package com.android.systemui.qs.tiles;
-import com.android.internal.util.ArrayUtils;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.UserAvatarView;
-
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -34,6 +29,11 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.util.ArrayUtils;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.UserAvatarView;
+
/**
* Displays one user in the {@link UserDetailView} view.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index 6eb0646..1565b6f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Pair;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.UserInfoController;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index b8310f2..e4fd31d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -34,6 +34,7 @@
import android.util.Log;
import android.view.Display;
import android.view.View;
+
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index 573db98..318c69f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -20,6 +20,7 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 61780f8..0115f91 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 49f2ab0..6b8968f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b78fd22..35e97e5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,10 +19,12 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
+import android.app.UiModeManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -36,6 +38,7 @@
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.View;
+
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -87,7 +90,10 @@
public final static String RECENTS_PACKAGE = "com.android.systemui";
public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
+ public final static String RECENTS_TV_ACTIVITY = "com.android.systemui.recents.tv.RecentsTvActivity";
+ //Used to store tv or non-tv activty for use in creating intents.
+ private final String mRecentsIntentActivityName;
/**
* An implementation of ITaskStackListener, that allows us to listen for changes to the system
* task stacks and update recents accordingly.
@@ -210,6 +216,14 @@
launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
launchOpts.onlyLoadForCache = true;
loader.loadTasks(mContext, plan, launchOpts);
+
+ //Manager used to determine if we are running on tv or not
+ UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
+ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
+ mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
+ } else {
+ mRecentsIntentActivityName = RECENTS_ACTIVITY;
+ }
}
public void onBootCompleted() {
@@ -906,10 +920,11 @@
launchState.launchedViaDragGesture = mDraggingInRecents;
Intent intent = new Intent();
- intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
+ intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
index 39d0d59..2c1158d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
+
import com.android.systemui.SystemUIApplication;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 10075bc..13d4acb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -39,6 +39,7 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.systemui.R;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index 212c7f4..0d56ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -27,6 +27,7 @@
import android.os.UserHandle;
import android.util.Log;
import android.util.MutableBoolean;
+
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import java.lang.ref.WeakReference;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
index 21b9301..3db106e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.activity;
import android.graphics.Rect;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
index 898d1fc..4140bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.component;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.misc.SystemServicesProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
index f9ccfc8..75e459a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.component;
import android.content.Context;
+
import com.android.systemui.recents.events.EventBus;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
index ad9feb6..c4b47c0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.ui;
import android.util.MutableInt;
+
import com.android.systemui.recents.events.EventBus;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
index b81c10c..b368bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.events.ui.dragndrop;
import android.graphics.Point;
+
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
index a91ea7e..acad0ea 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
+
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 96b5cac..843adc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -26,12 +26,11 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -61,8 +60,6 @@
private Rect mSystemInsets = new Rect();
private int mHeaderHeight;
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mFastOutLinearInInterpolator;
private int mHistoryTransitionDuration;
public RecentsHistoryView(Context context) {
@@ -84,10 +81,6 @@
mAdapter = new RecentsHistoryAdapter(context);
mItemTouchHandler = new RecentsHistoryItemTouchCallbacks(context, mAdapter);
mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
mViewBounds = new AnimateableViewBounds(this, 0);
setOutlineProvider(mViewBounds);
}
@@ -103,7 +96,7 @@
.alpha(1f)
.translationY(0f)
.setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setUpdateListener(this)
.start();
clearAllButton.setVisibility(View.VISIBLE);
@@ -111,7 +104,7 @@
clearAllButton.animate()
.alpha(1f)
.setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withLayer()
.start();
mAdapter.updateTasks(getContext(), stack);
@@ -130,7 +123,7 @@
.alpha(0f)
.translationY(-stackHeight * TRANSLATION_Y_PCT)
.setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
.setUpdateListener(this)
.withEndAction(new Runnable() {
@Override
@@ -143,7 +136,7 @@
.alpha(0f)
.translationY(0f)
.setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 2882cec..ecf8ecb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -65,6 +65,7 @@
import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+
import com.android.internal.app.AssistUtils;
import com.android.internal.os.BackgroundThread;
import com.android.systemui.Prefs;
@@ -81,6 +82,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
/**
@@ -266,8 +268,9 @@
ComponentName topActivity = topTask.topActivity;
// Check if the front most activity is recents
- if (topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
- topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)) {
+ if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
+ (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
+ topActivity.getClassName().equals(RecentsImpl.RECENTS_TV_ACTIVITY)))) {
if (isHomeTopMost != null) {
isHomeTopMost.value = false;
}
@@ -356,6 +359,13 @@
}
/**
+ * Returns whether the given stack id is the pinned stack id.
+ */
+ public static boolean isPinnedStack(int stackId){
+ return stackId == PINNED_STACK_ID;
+ }
+
+ /**
* Returns whether the given stack id is the docked stack id.
*/
public static boolean isDockedStack(int stackId) {
@@ -968,4 +978,20 @@
public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
mWm.requestAppKeyboardShortcuts(receiver);
}
+
+ public void focusPinnedStack() {
+ try {
+ mIam.setFocusedStack(PINNED_STACK_ID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void focusHomeStack() {
+ try {
+ mIam.setFocusedStack(HOME_STACK_ID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index f3c4cc3..4deea54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -26,6 +26,7 @@
import android.util.Property;
import android.view.View;
import android.view.ViewParent;
+
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskViewTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index d9057b8..1f82c16 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.UserHandle;
+
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 3029acf..4e08bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -22,12 +22,12 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.os.Debug;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.SparseIntArray;
+
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 5c77d8a..26130ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -29,6 +29,7 @@
import android.os.HandlerThread;
import android.util.Log;
import android.util.LruCache;
+
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 193bd17..1c277d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -23,6 +23,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 66eeac6..9bf48bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -33,6 +33,7 @@
import android.util.ArraySet;
import android.util.SparseArray;
import android.view.animation.Interpolator;
+
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
new file mode 100644
index 0000000..b4ee42b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -0,0 +1,454 @@
+/*
+ * 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 com.android.systemui.recents.tv;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.RecentsTvView;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.tv.pip.PipManager;
+
+import java.util.ArrayList;
+/**
+ * The main TV recents activity started by the RecentsImpl.
+ */
+public class RecentsTvActivity extends Activity implements OnPreDrawListener {
+ private final static String TAG = "RecentsTvActivity";
+ private final static boolean DEBUG = false;
+
+ public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
+
+ private boolean mFinishedOnStartup;
+ private RecentsPackageMonitor mPackageMonitor;
+ private long mLastTabKeyEventTime;
+ private boolean mIgnoreAltTabRelease;
+
+ private RecentsTvView mRecentsView;
+ private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
+ private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+
+
+ /**
+ * A common Runnable to finish Recents by launching Home with an animation depending on the
+ * last activity launch state. Generally we always launch home when we exit Recents rather than
+ * just finishing the activity since we don't know what is behind Recents in the task stack.
+ */
+ class FinishRecentsRunnable implements Runnable {
+ Intent mLaunchIntent;
+
+ /**
+ * Creates a finish runnable that starts the specified intent.
+ */
+ public FinishRecentsRunnable(Intent launchIntent) {
+ mLaunchIntent = launchIntent;
+ }
+
+ @Override
+ public void run() {
+ try {
+ RecentsActivityLaunchState launchState =
+ Recents.getConfiguration().getLaunchState();
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsTvActivity.this,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_enter :
+ R.anim.recents_to_launcher_enter,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_exit :
+ R.anim.recents_to_launcher_exit);
+ startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+ } catch (Exception e) {
+ Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
+ }
+ }
+ }
+
+ private void updateRecentsTasks() {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
+ if (plan == null) {
+ plan = loader.createLoadPlan(this);
+ }
+
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ if (!plan.hasTasks()) {
+ loader.preloadTasks(plan, -1, launchState.launchedFromHome);
+ }
+ TaskStack stack = plan.getTaskStack();
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.runningTaskId = launchState.launchedToTaskId;
+ loadOpts.numVisibleTasks = stack.getStackTaskCount();
+ loadOpts.numVisibleTaskThumbnails = stack.getStackTaskCount();
+ loader.loadTasks(this, plan, loadOpts);
+
+
+ mRecentsView.setTaskStack(stack);
+ if (mTaskStackViewAdapter == null) {
+ mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+ mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
+ } else {
+ mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+ }
+
+ if (launchState.launchedToTaskId != -1) {
+ ArrayList<Task> tasks = stack.getStackTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task t = tasks.get(i);
+ if (t.key.id == launchState.launchedToTaskId) {
+ t.isLaunchTarget = true;
+ break;
+ }
+ }
+ }
+ }
+
+ boolean dismissRecentsToLaunchTargetTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // If we have a focused Task, launch that Task now
+ if (mRecentsView.launchPreviousTask()) return true;
+ // If none of the other cases apply, then just go Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ }
+ return false;
+ }
+
+ boolean dismissRecentsToFocusedTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // If we have a focused Task, launch that Task now
+ if (mRecentsView.launchFocusedTask()) return true;
+ // If none of the other cases apply, then just go Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ return true;
+ }
+ return false;
+ }
+
+ void dismissRecentsToHome(boolean animateTaskViews) {
+ DismissRecentsToHomeAnimationStarted dismissEvent =
+ new DismissRecentsToHomeAnimationStarted(animateTaskViews);
+ dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+ dismissEvent.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ }
+ });
+ EventBus.getDefault().send(dismissEvent);
+ }
+
+ boolean dismissRecentsToHomeIfVisible(boolean animated) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+ // Return to Home
+ dismissRecentsToHome(animated);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mFinishedOnStartup = false;
+
+ // In the case that the activity starts up before the Recents component has initialized
+ // (usually when debugging/pushing the SysUI apk), just finish this activity.
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp == null) {
+ mFinishedOnStartup = true;
+ finish();
+ return;
+ }
+
+ // Register this activity with the event bus
+ EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
+ mPackageMonitor = new RecentsPackageMonitor();
+ mPackageMonitor.register(this);
+
+ // Set the Recents layout
+ setContentView(R.layout.recents_on_tv);
+
+ mRecentsView = (RecentsTvView) findViewById(R.id.recents_view);
+ mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+
+ // Create the home intent runnable
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ // Update the recent tasks
+ updateRecentsTasks();
+
+ // If this is a new instance from a configuration change, then we have to manually trigger
+ // the enter animation state, or if recents was relaunched by AM, without going through
+ // the normal mechanisms
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+ !launchState.launchedFromAppWithThumbnail;
+ if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ // Notify that recents is now visible
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+ }
+
+ @Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ mIgnoreAltTabRelease = false;
+ // Notify that recents is now hidden
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+
+ // Workaround for b/22542869, if the RecentsActivity is started again, but without going
+ // through SystemUI, we need to reset the config launch flags to ensure that we do not
+ // wait on the system to send a signal that was never queued.
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ launchState.launchedFromHome = false;
+ launchState.launchedFromSearchHome = false;
+ launchState.launchedFromAppWithThumbnail = false;
+ launchState.launchedToTaskId = -1;
+ launchState.launchedWithAltTab = false;
+ launchState.launchedHasConfigurationChanged = false;
+ launchState.launchedViaDragGesture = false;
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ // In the case that the activity finished on startup, just skip the unregistration below
+ if (mFinishedOnStartup) {
+ return;
+ }
+
+ // Unregister any broadcast receivers for the task loader
+ mPackageMonitor.unregister();
+
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ if (loader != null) {
+ loader.onTrimMemory(level);
+ }
+ }
+
+ @Override
+ public void onMultiWindowModeChanged(boolean multiWindowMode) {
+ super.onMultiWindowModeChanged(multiWindowMode);
+ if (!multiWindowMode) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.loadIcons = false;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1, false);
+ loader.loadTasks(this, loadPlan, launchOpts);
+ EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP: {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ PipManager.getInstance().showPipMenu();
+ ssp.focusPinnedStack();
+ return true;
+ }
+ case KeyEvent.KEYCODE_DPAD_DOWN: {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ PipManager.getInstance().showPipOverlay(false);
+ ssp.focusHomeStack();
+ return true;
+ }
+ case KeyEvent.KEYCODE_DEL:
+ case KeyEvent.KEYCODE_FORWARD_DEL: {
+ EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+ return true;
+ }
+ default:
+ break;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public void onUserInteraction() {
+ EventBus.getDefault().send(new UserInteractionEvent());
+ }
+
+ @Override
+ public void onBackPressed() {
+ // Back behaves like the recents button so just trigger a toggle event
+ EventBus.getDefault().send(new ToggleRecentsEvent());
+ }
+
+ /**** EventBus events ****/
+
+ public final void onBusEvent(ToggleRecentsEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ if (launchState.launchedFromHome) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
+ }
+
+ public final void onBusEvent(HideRecentsEvent event) {
+ if (event.triggeredFromAltTab) {
+ // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
+ if (!mIgnoreAltTabRelease) {
+ dismissRecentsToFocusedTaskOrHome();
+ }
+ } else if (event.triggeredFromHomeKey) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ // Do nothing
+ }
+ }
+
+ public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+ EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+ mRecentsView.invalidate();
+ }
+
+ public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ int launchToTaskId = launchState.launchedToTaskId;
+ if (launchToTaskId != -1 &&
+ (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.cancelWindowTransition(launchState.launchedToTaskId);
+ ssp.cancelThumbnailTransition(getTaskId());
+ }
+ }
+
+ public final void onBusEvent(DeleteTaskDataEvent event) {
+ // Remove any stored data from the loader
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ loader.deleteTaskData(event.task, false);
+
+ // Remove the task from activity manager
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.removeTask(event.task.key.id);
+ }
+
+ public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.hasDockedTask()) {
+ mRecentsView.showEmptyView();
+ } else {
+ // Just go straight home (no animation necessary because there are no more task views)
+ dismissRecentsToHome(false /* animateTaskViews */);
+ }
+ }
+
+ public final void onBusEvent(LaunchTaskFailedEvent event) {
+ // Return to Home
+ dismissRecentsToHome(true /* animateTaskViews */);
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+ // We post to make sure that this information is delivered after this traversals is
+ // finished.
+ mRecentsView.post(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().endProlongedAnimations();
+ }
+ });
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
new file mode 100644
index 0000000..8028327
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -0,0 +1,144 @@
+/*
+ * 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 com.android.systemui.recents.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
+
+public class ViewFocusAnimator implements View.OnFocusChangeListener {
+ private final float mUnselectedScale;
+ private final float mSelectedScaleDelta;
+ private final float mUnselectedZ;
+ private final float mSelectedZDelta;
+ private final int mAnimDuration;
+ private final Interpolator mFocusInterpolator;
+
+ protected View mTargetView;
+ private float mFocusProgress;
+
+ ObjectAnimator mFocusAnimation;
+
+ public ViewFocusAnimator(View view) {
+ mTargetView = view;
+ final Resources res = view.getResources();
+
+ mTargetView.setOnFocusChangeListener(this);
+
+ TypedValue out = new TypedValue();
+ res.getValue(R.raw.unselected_scale, out, true);
+ mUnselectedScale = out.getFloat();
+ mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
+ mUnselectedScale;
+
+ mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
+ mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
+
+ mAnimDuration = res.getInteger(R.integer.item_scale_anim_duration);
+
+ mFocusInterpolator = new AccelerateDecelerateInterpolator();
+
+ mFocusAnimation = ObjectAnimator.ofFloat(this, "focusProgress", 0.0f);
+ mFocusAnimation.setDuration(mAnimDuration);
+ mFocusAnimation.setInterpolator(mFocusInterpolator);
+
+ setFocusProgress(0.0f);
+
+ mFocusAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTargetView.setHasTransientState(true);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTargetView.setHasTransientState(false);
+ }
+ });
+ }
+
+ public void setFocusProgress(float level) {
+ mFocusProgress = level;
+
+ float scale = mUnselectedScale + (level * mSelectedScaleDelta);
+ float z = mUnselectedZ + (level * mSelectedZDelta);
+
+ mTargetView.setScaleX(scale);
+ mTargetView.setScaleY(scale);
+ mTargetView.setZ(z);
+ }
+
+ public float getFocusProgress() {
+ return mFocusProgress;
+ }
+
+ public void animateFocus(boolean focused) {
+ if (mFocusAnimation.isStarted()) {
+ mFocusAnimation.cancel();
+ }
+
+ float target = focused ? 1.0f : 0.0f;
+
+ if (getFocusProgress() != target) {
+ mFocusAnimation.setFloatValues(getFocusProgress(), target);
+ mFocusAnimation.start();
+ }
+ }
+
+ public void setFocusImmediate(boolean focused) {
+ if (mFocusAnimation.isStarted()) {
+ mFocusAnimation.cancel();
+ }
+
+ float target = focused ? 1.0f : 0.0f;
+
+ setFocusProgress(target);
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v != mTargetView) {
+ return;
+ }
+ changeSize(hasFocus);
+ }
+
+ protected void changeSize(boolean hasFocus) {
+ ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
+ int width = lp.width;
+ int height = lp.height;
+
+ if (width < 0 && height < 0) {
+ mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ height = mTargetView.getMeasuredHeight();
+ }
+
+ if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
+ mTargetView.getVisibility() == View.VISIBLE) {
+ animateFocus(hasFocus);
+ } else {
+ setFocusImmediate(hasFocus);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
new file mode 100644
index 0000000..9193114
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -0,0 +1,249 @@
+/*
+ * 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 com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView.
+ */
+public class RecentsTvView extends FrameLayout {
+
+ private static final String TAG = "RecentsTvView";
+ private static final boolean DEBUG = false;
+
+ private TaskStack mStack;
+ private TaskStackHorizontalGridView mTaskStackHorizontalView;
+ private View mEmptyView;
+ private boolean mAwaitingFirstLayout = true;
+ private Rect mSystemInsets = new Rect();
+
+
+ public RecentsTvView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ setWillNotDraw(false);
+
+ LayoutInflater inflater = LayoutInflater.from(context);
+ mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+ addView(mEmptyView);
+ }
+
+ public void setTaskStack(TaskStack stack) {
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ mStack = stack;
+
+ if (mTaskStackHorizontalView != null) {
+ mTaskStackHorizontalView.reset();
+ mTaskStackHorizontalView.setStack(stack);
+ } else {
+ mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
+ mTaskStackHorizontalView.setStack(stack);
+ }
+
+
+ if (stack.getStackTaskCount() > 0) {
+ hideEmptyView();
+ } else {
+ showEmptyView();
+ }
+
+ requestLayout();
+ }
+
+ public Task getNextTaskOrTopTask(Task taskToSearch) {
+ Task returnTask = null;
+ boolean found = false;
+ if (mTaskStackHorizontalView != null) {
+ TaskStack stack = mTaskStackHorizontalView.getStack();
+ ArrayList<Task> taskList = stack.getStackTasks();
+ // Iterate the stack views and try and find the focused task
+ for (int j = taskList.size() - 1; j >= 0; --j) {
+ Task task = taskList.get(j);
+ // Return the next task in the line.
+ if (found)
+ return task;
+ // Remember the first possible task as the top task.
+ if (returnTask == null)
+ returnTask = task;
+ if (task == taskToSearch)
+ found = true;
+ }
+ }
+ return returnTask;
+ }
+
+ public boolean launchFocusedTask() {
+ if (mTaskStackHorizontalView != null) {
+ Task task = mTaskStackHorizontalView.getFocusedTask();
+ if (task != null) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Launches the task that recents was launched from if possible */
+ public boolean launchPreviousTask() {
+ if (mTaskStackHorizontalView != null) {
+ TaskStack stack = mTaskStackHorizontalView.getStack();
+ Task task = stack.getLaunchTarget();
+ if (task != null) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Launches a given task. */
+ public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
+ if (mTaskStackHorizontalView != null) {
+ // Iterate the stack views and try and find the given task.
+ List<TaskCardView> taskViews = mTaskStackHorizontalView.getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int j = 0; j < taskViewCount; j++) {
+ TaskCardView tv = taskViews.get(j);
+ if (tv.getTask() == task) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Hides the task stack and shows the empty view.
+ */
+ public void showEmptyView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mEmptyView.bringToFront();
+ }
+
+ /**
+ * Shows the task stack and hides the empty view.
+ */
+ public void hideEmptyView() {
+ mEmptyView.setVisibility(View.INVISIBLE);
+ }
+
+ /**
+ * Returns the last known system insets.
+ */
+ public Rect getSystemInsets() {
+ return mSystemInsets;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+
+ /**
+ * This is called with the full size of the window since we are handling our own insets.
+ */
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mTaskStackHorizontalView != null && mTaskStackHorizontalView.getVisibility() != GONE) {
+ mTaskStackHorizontalView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
+ }
+
+ // Layout the empty view
+ mEmptyView.layout(left, top, right, bottom);
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mSystemInsets.set(insets.getSystemWindowInsets());
+ requestLayout();
+ return insets;
+ }
+
+ /**** EventBus Events ****/
+
+ public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+ // If we are going home, cancel the previous task's window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+ }
+
+ public final void onBusEvent(TaskStackUpdatedEvent event) {
+ mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+ mStack.createAffiliatedGroupings(getContext());
+ }
+
+
+ public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+ if (!event.visible) {
+ // Reset the view state
+ mAwaitingFirstLayout = true;
+ }
+ }
+
+
+ public void setTaskStackViewAdapter(TaskStackHorizontalViewAdapter taskStackViewAdapter) {
+ if(mTaskStackHorizontalView != null) {
+ mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
new file mode 100644
index 0000000..e275f22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+
+public class TaskCardView extends RelativeLayout {
+
+ private ImageView mThumbnailView;
+ private TextView mTitleTextView;
+ private TextView mContentTextView;
+ private ImageView mBadgeView;
+ private Task mTask;
+
+ private ViewFocusAnimator mViewFocusAnimator;
+
+ public TaskCardView(Context context) {
+ this(context, null);
+ }
+
+ public TaskCardView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mViewFocusAnimator = new ViewFocusAnimator(this);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+ mTitleTextView = (TextView) findViewById(R.id.card_title_text);
+ mContentTextView = (TextView) findViewById(R.id.card_content_text);
+ mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
+ }
+
+ public void init(Task task) {
+ mTask = task;
+ mThumbnailView.setImageBitmap(task.thumbnail);
+ mTitleTextView.setText(task.title);
+ mContentTextView.setText(task.contentDescription);
+ mBadgeView.setImageDrawable(task.icon);
+ }
+
+ public Task getTask() {
+ return mTask;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
new file mode 100644
index 0000000..2d41742
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -0,0 +1,158 @@
+/*
+ * 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 com.android.systemui.recents.tv.views;
+
+
+import android.content.Context;
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
+import com.android.systemui.recents.views.TaskViewAnimation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Horizontal Grid View Implementation to show the Task Stack for TV.
+ */
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+
+ private TaskStack mStack;
+ private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
+ private Task mFocusedTask;
+
+
+ public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ setItemMargin((int) getResources().getDimension(R.dimen.recents_tv_gird_card_spacing));
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+ /**
+ * Resets this view for reuse.
+ */
+ public void reset() {
+ // Reset the focused task
+ resetFocusedTask(getFocusedTask());
+ requestLayout();
+ }
+
+ /**
+ * @param task - Task to reset
+ */
+ private void resetFocusedTask(Task task) {
+ if (task != null) {
+ TaskCardView tv = getChildViewForTask(task);
+ if (tv != null) {
+ tv.requestFocus();
+ }
+ }
+ mFocusedTask = null;
+ }
+
+ /**
+ * Sets the task stack.
+ * @param stack
+ */
+ public void setStack(TaskStack stack) {
+ //Set new stack
+ mStack = stack;
+ if (mStack != null) {
+ mStack.setCallbacks(this);
+ }
+ //Layout with new stack
+ requestLayout();
+ }
+
+ /**
+ * @return Returns the task stack.
+ */
+ public TaskStack getStack() {
+ return mStack;
+ }
+
+ /**
+ * @return - The focused task.
+ */
+ public Task getFocusedTask() {
+ return mFocusedTask;
+ }
+
+ /**
+ * @param task
+ * @return Child view for given task
+ */
+ public TaskCardView getChildViewForTask(Task task) {
+ List<TaskCardView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskCardView tv = taskViews.get(i);
+ if (tv.getTask() == task) {
+ return tv;
+ }
+ }
+ return null;
+ }
+
+ public List<TaskCardView> getTaskViews() {
+ return mTaskViews;
+ }
+
+ @Override
+ public void onStackTaskAdded(TaskStack stack, Task newTask){
+ getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
+ }
+
+ @Override
+ public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
+ Task newFrontMostTask, TaskViewAnimation animation) {
+ getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
+ if (mFocusedTask == removedTask) {
+ resetFocusedTask(removedTask);
+ }
+ // If there are no remaining tasks, then just close recents
+ if (mStack.getStackTaskCount() == 0) {
+ boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
+ if (shouldFinishActivity) {
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+ }
+ }
+ }
+
+ @Override
+ public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation) {
+ //No history task on tv
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
new file mode 100644
index 0000000..7b62f4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.android.systemui.recents.tv.views;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskStackHorizontalViewAdapter extends
+ RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
+
+ private static final String TAG = "TaskStackHorizontalViewAdapter";
+ private List<Task> mTaskList;
+
+ static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
+ private TaskCardView mTaskCardView;
+ private Task mTask;
+ public ViewHolder(View v) {
+ super(v);
+ if(v instanceof TaskCardView) {
+ mTaskCardView = (TaskCardView) v;
+ }
+ }
+
+ public void init(Task task) {
+ mTaskCardView.init(task);
+ mTask = task;
+ mTaskCardView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ try {
+ ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+ ((Activity)(v.getContext())).finish();
+ } catch (Exception e) {
+ Log.e(TAG, v.getContext()
+ .getString(R.string.recents_launch_error_message, mTask.title), e);
+ }
+
+ }
+ }
+
+ public TaskStackHorizontalViewAdapter(List tasks) {
+ mTaskList = new ArrayList<>(tasks);
+ }
+
+ public void setNewStackTasks(List tasks) {
+ mTaskList.clear();
+ mTaskList.addAll(tasks);
+ notifyDataSetChanged();
+ }
+ @Override
+ public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.recents_task_card_view, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.init(mTaskList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mTaskList.size();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 682fd8f..d64a676 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -28,6 +28,7 @@
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.Log;
+
import com.android.systemui.R;
import com.android.systemui.recents.RecentsConfiguration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 491c4c2..511aa3c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.graphics.RectF;
import android.util.ArrayMap;
+
import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index b363ed5..3fdd771 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -31,6 +31,7 @@
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.WindowManagerGlobal;
+
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index b59ff30..e2ff52c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -35,13 +35,12 @@
import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -76,7 +75,6 @@
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
import java.util.List;
@@ -113,9 +111,6 @@
private RecentsTransitionHelper mTransitionHelper;
private RecentsViewTouchHandler mTouchHandler;
-
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mFastOutLinearInInterpolator;
private final FlingAnimationUtils mFlingAnimationUtils;
public RecentsView(Context context) {
@@ -137,10 +132,6 @@
SystemServicesProxy ssp = Recents.getSystemServices();
mHandler = new Handler();
mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
mDividerSize = ssp.getDockedDividerSize(context);
mTouchHandler = new RecentsViewTouchHandler(this);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
@@ -597,7 +588,7 @@
tmpTransform.scale = 1f;
tmpTransform.rect.set(taskViewRect);
mTaskStackView.updateTaskViewToTransform(event.taskView, tmpTransform,
- new TaskViewAnimation(125, PhoneStatusBar.ALPHA_OUT,
+ new TaskViewAnimation(125, Interpolators.ALPHA_OUT,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -609,7 +600,7 @@
// Animate the stack accordingly
TaskViewAnimation stackAnim = new TaskViewAnimation(
TaskStackView.DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator);
+ Interpolators.FAST_OUT_SLOW_IN);
mTaskStackView.getStack().removeTask(event.task, stackAnim);
}
}));
@@ -731,7 +722,7 @@
.alpha(0f)
.translationY(stackRect.height() / 2)
.setDuration(historyTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -756,7 +747,7 @@
.alpha(1f)
.translationY(0)
.setDuration(historyTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
}
@@ -794,7 +785,7 @@
mHistoryButton.animate()
.alpha(1f)
.setDuration(duration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withLayer()
.start();
}
@@ -825,7 +816,7 @@
mHistoryButton.animate()
.alpha(0f)
.setDuration(duration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -854,7 +845,7 @@
if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
// This is no longer visible, so hide it
viewState.startAnimation(null, 0, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
- PhoneStatusBar.ALPHA_OUT, animateAlpha, animateBounds);
+ Interpolators.ALPHA_OUT, animateAlpha, animateBounds);
} else {
// This state is now visible, update the bounds and show it
int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha);
@@ -867,7 +858,7 @@
viewState.dockAreaOverlay.setBounds(bounds);
}
viewState.startAnimation(bounds, alpha, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
- PhoneStatusBar.ALPHA_IN, animateAlpha, animateBounds);
+ Interpolators.ALPHA_IN, animateAlpha, animateBounds);
}
}
}
@@ -882,8 +873,8 @@
mBackgroundScrim.getAlpha(), alphaInt);
mBackgroundScrimAnimator.setDuration(duration);
mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
- ? PhoneStatusBar.ALPHA_OUT
- : PhoneStatusBar.ALPHA_IN);
+ ? Interpolators.ALPHA_OUT
+ : Interpolators.ALPHA_IN);
mBackgroundScrimAnimator.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index d8698ee..288fcab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -20,6 +20,7 @@
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 2254dfc..e8fa398 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -19,8 +19,8 @@
import android.app.Activity;
import android.content.Context;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
@@ -37,18 +37,11 @@
int mNavBarScrimEnterDuration;
- Interpolator mFastOutSlowInInterpolator;
- Interpolator mQuintOutInterpolator;
-
public SystemBarScrimViews(Activity activity) {
mContext = activity;
mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
mNavBarScrimEnterDuration = activity.getResources().getInteger(
R.integer.recents_nav_bar_scrim_enter_duration);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(activity,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mQuintOutInterpolator = AnimationUtils.loadInterpolator(activity,
- com.android.internal.R.interpolator.decelerate_quint);
}
/**
@@ -74,7 +67,7 @@
mNavBarScrimView.animate()
.translationY(0)
.setDuration(mNavBarScrimEnterDuration)
- .setInterpolator(mQuintOutInterpolator)
+ .setInterpolator(Interpolators.DECELERATE_QUINT)
.withStartAction(new Runnable() {
@Override
public void run() {
@@ -97,7 +90,7 @@
.translationY(mNavBarScrimView.getMeasuredHeight())
.setStartDelay(0)
.setDuration(taskViewExitToAppDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index d550d83..682c298 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -22,8 +22,8 @@
import android.content.res.Resources;
import android.graphics.RectF;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -31,7 +31,6 @@
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.List;
@@ -66,20 +65,10 @@
private TaskStackView mStackView;
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mFastOutLinearInInterpolator;
- private Interpolator mQuintOutInterpolator;
-
private TaskViewTransform mTmpTransform = new TaskViewTransform();
public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
mStackView = stackView;
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.decelerate_quint);
}
/**
@@ -198,7 +187,7 @@
// Animate the task up if it was occluding the launch target
if (currentTaskOccludesLaunchTarget) {
TaskViewAnimation taskAnimation = new TaskViewAnimation(
- taskViewEnterFromAffiliatedAppDuration, PhoneStatusBar.ALPHA_IN,
+ taskViewEnterFromAffiliatedAppDuration, Interpolators.ALPHA_IN,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -219,7 +208,7 @@
frontIndex * taskViewEnterFromHomeStaggerDelay;
TaskViewAnimation taskAnimation = new TaskViewAnimation(delay,
- duration, mQuintOutInterpolator,
+ duration, Interpolators.DECELERATE_QUINT,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
@@ -253,7 +242,7 @@
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
TaskViewAnimation taskAnimation = new TaskViewAnimation(
- animated ? taskViewExitToHomeDuration : 0, mFastOutLinearInInterpolator,
+ animated ? taskViewExitToHomeDuration : 0, Interpolators.FAST_OUT_LINEAR_IN,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
@@ -295,7 +284,7 @@
} else if (currentTaskOccludesLaunchTarget) {
// Animate this task out of view
TaskViewAnimation taskAnimation = new TaskViewAnimation(
- taskViewExitToAppDuration, PhoneStatusBar.ALPHA_OUT,
+ taskViewExitToAppDuration, Interpolators.ALPHA_OUT,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
@@ -327,7 +316,7 @@
// Compose the new animation and transform and star the animation
TaskViewAnimation taskAnimation = new TaskViewAnimation(taskViewRemoveAnimDuration,
- PhoneStatusBar.ALPHA_OUT, new AnimatorListenerAdapter() {
+ Interpolators.ALPHA_OUT, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
postAnimationTrigger.decrement();
@@ -364,7 +353,7 @@
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
TaskViewAnimation taskAnimation = new TaskViewAnimation(startDelayIncr * i,
- historyTransitionDuration, mFastOutSlowInInterpolator,
+ historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN,
postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
@@ -393,7 +382,7 @@
for (int i = taskViewCount - 1; i >= 0; i--) {
TaskView tv = taskViews.get(i);
TaskViewAnimation taskAnimation = new TaskViewAnimation(startDelayIncr * i,
- historyTransitionDuration, mFastOutSlowInInterpolator);
+ historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN);
stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(),
mTmpTransform, null);
mTmpTransform.alpha = 1f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index bb37c04..7c695ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -25,8 +25,8 @@
import android.util.ArraySet;
import android.util.FloatProperty;
import android.util.Property;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -212,7 +212,6 @@
}
Context mContext;
- private Interpolator mLinearOutSlowInInterpolator;
private StackState mState = StackState.SPLIT;
private TaskStackLayoutAlgorithmCallbacks mCb;
@@ -299,8 +298,6 @@
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
}
/**
@@ -489,7 +486,7 @@
newState);
mFocusStateAnimator.setDuration(mContext.getResources().getInteger(
R.integer.recents_animate_task_stack_scroll_duration));
- mFocusStateAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+ mFocusStateAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mFocusStateAnimator.start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 79f6381..264cede 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -36,9 +36,10 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -148,8 +149,6 @@
TaskViewTransform mTmpTransform = new TaskViewTransform();
LayoutInflater mInflater;
- Interpolator mFastOutSlowInInterpolator;
-
// A convenience update listener to request updating clipping of tasks
private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
new ValueAnimator.AnimatorUpdateListener() {
@@ -200,8 +199,6 @@
mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
mAnimationHelper = new TaskStackAnimationHelper(context, this);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
mTaskCornerRadiusPx = res.getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
mDividerSize = ssp.getDockedDividerSize(context);
@@ -1227,7 +1224,7 @@
// Animate in the freeform workspace
animateFreeformWorkspaceBackgroundAlpha(
mLayoutAlgorithm.getStackState().freeformBackgroundAlpha, 150,
- mFastOutSlowInInterpolator);
+ Interpolators.FAST_OUT_SLOW_IN);
// Set the task focused state without requesting view focus, and leave the focus animations
// until after the enter-animation
@@ -1321,7 +1318,7 @@
// Animate all the tasks into place
relayoutTaskViews(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator));
+ Interpolators.FAST_OUT_SLOW_IN));
}
/**
@@ -1534,7 +1531,7 @@
int taskViewExitToHomeDuration = getResources().getInteger(
R.integer.recents_task_exit_to_home_duration);
animateFreeformWorkspaceBackgroundAlpha(0, taskViewExitToHomeDuration,
- mFastOutSlowInInterpolator);
+ Interpolators.FAST_OUT_SLOW_IN);
}
public final void onBusEvent(DismissFocusedTaskViewEvent event) {
@@ -1600,7 +1597,7 @@
mTmpTransform.scale = finalScale;
mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1;
updateTaskViewToTransform(event.taskView, mTmpTransform,
- new TaskViewAnimation(DRAG_SCALE_DURATION, mFastOutSlowInInterpolator));
+ new TaskViewAnimation(DRAG_SCALE_DURATION, Interpolators.FAST_OUT_SLOW_IN));
}
public final void onBusEvent(DragStartInitializeDropTargetsEvent event) {
@@ -1612,7 +1609,7 @@
}
public final void onBusEvent(DragDropTargetChangedEvent event) {
- TaskViewAnimation animation = new TaskViewAnimation(250, mFastOutSlowInInterpolator);
+ TaskViewAnimation animation = new TaskViewAnimation(250, Interpolators.FAST_OUT_SLOW_IN);
if (event.dropTarget instanceof TaskStack.DockState) {
// Calculate the new task stack bounds that matches the window size that Recents will
// have after the drop
@@ -1686,9 +1683,9 @@
mTmpTransform, null);
event.getAnimationTrigger().increment();
relayoutTaskViews(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator));
+ Interpolators.FAST_OUT_SLOW_IN));
updateTaskViewToTransform(event.taskView, mTmpTransform,
- new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, mFastOutSlowInInterpolator,
+ new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
event.getAnimationTrigger().decrementOnAnimationEnd()));
removeIgnoreTask(event.task);
}
@@ -1789,7 +1786,7 @@
// Remove the task from the stack
mStack.removeTask(task, new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
- mFastOutSlowInInterpolator));
+ Interpolators.FAST_OUT_SLOW_IN));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 4ec051f..7884bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -23,9 +23,9 @@
import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.OverScroller;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.misc.Utilities;
@@ -69,16 +69,12 @@
ObjectAnimator mScrollAnimator;
float mFinalAnimatedScroll;
- private Interpolator mLinearOutSlowInInterpolator;
-
public TaskStackViewScroller(Context context, TaskStackViewScrollerCallbacks cb,
TaskStackLayoutAlgorithm layoutAlgorithm) {
mContext = context;
mCb = cb;
mScroller = new OverScroller(context);
mLayoutAlgorithm = layoutAlgorithm;
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
}
/** Resets the task scroller. */
@@ -192,7 +188,7 @@
mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, curScroll, newScroll);
mScrollAnimator.setDuration(mContext.getResources().getInteger(
R.integer.recents_animate_task_stack_scroll_duration));
- mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+ mScrollAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mScrollAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 7019444..da99956 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -31,7 +31,9 @@
import android.view.ViewParent;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.recents.Constants;
@@ -121,7 +123,7 @@
@Override
protected void prepareSnapBackAnimation(View v, Animator anim) {
- anim.setInterpolator(mSv.mFastOutSlowInInterpolator);
+ anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mSwipeHelperAnimations.put(v, anim);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 5a4064a..2e8e665 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -37,8 +37,8 @@
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -54,7 +54,6 @@
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
@@ -128,8 +127,6 @@
Point mDownTouchPos = new Point();
- Interpolator mFastOutSlowInInterpolator;
-
public TaskView(Context context) {
this(context, null);
}
@@ -149,8 +146,6 @@
mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius));
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
if (config.fakeShadows) {
setBackground(new FakeShadowDrawable(res, config));
}
@@ -456,7 +451,7 @@
.scaleX(1f)
.scaleY(1f)
.setDuration(fadeInDuration)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .setInterpolator(Interpolators.ALPHA_IN)
.start();
} else {
mActionButtonView.setScaleX(1f);
@@ -483,7 +478,7 @@
mActionButtonView.animate()
.alpha(0f)
.setDuration(fadeOutDuration)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -529,7 +524,7 @@
if (mDimAlpha > 0) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
anim.setDuration(duration);
- anim.setInterpolator(PhoneStatusBar.ALPHA_OUT);
+ anim.setInterpolator(Interpolators.ALPHA_OUT);
anim.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
index 74b16d0..5455042 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
@@ -19,7 +19,8 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
+
+import com.android.systemui.Interpolators;
import java.util.List;
@@ -29,7 +30,7 @@
public class TaskViewAnimation {
public static final TaskViewAnimation IMMEDIATE = new TaskViewAnimation(0,
- new LinearInterpolator());
+ Interpolators.LINEAR);
public final int startDelay;
public final int duration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 36760f7..408ffb4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -37,13 +37,13 @@
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewStub;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
@@ -163,10 +163,6 @@
// Header dim, which is only used when task view hardware layers are not used
private Paint mDimLayerPaint = new Paint();
- Interpolator mFastOutSlowInInterpolator;
- Interpolator mFastOutLinearInInterpolator;
- Interpolator mLinearOutSlowInInterpolator;
-
private CountDownTimer mFocusTimerCountDown;
public TaskViewHeader(Context context) {
@@ -200,13 +196,6 @@
mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
-
// Configure the background and dim
mBackground = new HighlightColorDrawable();
mBackground.setColorAndDim(Color.argb(255, 0, 0, 0), 0f);
@@ -440,7 +429,7 @@
mDismissButton.animate()
.alpha(1f)
.setStartDelay(0)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
.setDuration(getResources().getInteger(
R.integer.recents_task_enter_from_app_duration))
.start();
@@ -557,7 +546,7 @@
Animator revealAnim = ViewAnimationUtils.createCircularReveal(mAppOverlayView, x, y, 0,
getWidth());
revealAnim.setDuration(OVERLAY_REVEAL_DURATION);
- revealAnim.setInterpolator(mLinearOutSlowInInterpolator);
+ revealAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
revealAnim.start();
}
@@ -578,7 +567,7 @@
Animator revealAnim = ViewAnimationUtils.createCircularReveal(mAppOverlayView, x, y,
getWidth(), 0);
revealAnim.setDuration(OVERLAY_REVEAL_DURATION);
- revealAnim.setInterpolator(mLinearOutSlowInInterpolator);
+ revealAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
revealAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index c3a0ac9..ea40644 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -28,8 +28,7 @@
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
@@ -52,8 +51,6 @@
BitmapShader mBitmapShader;
LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
- Interpolator mFastOutSlowInInterpolator;
-
// Task bar clipping, the top of this thumbnail can be clipped against the opaque header
// bar that overlaps this thumbnail
View mTaskBar;
@@ -82,8 +79,6 @@
mDrawPaint.setAntiAlias(true);
mCornerRadius = getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index d8a202c..dd80750 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.UserHandle;
public abstract class CurrentUserTracker extends BroadcastReceiver {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
index 8829794..722aba5 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.SeekBar;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index dca7fd9..0b20f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -46,9 +46,9 @@
import android.widget.FrameLayout;
import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 01bfcea..874defa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -32,6 +32,7 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 90f7c08..7670223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -21,7 +21,6 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageView;
import android.widget.RemoteViews.RemoteView;
@RemoteView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 240d32e..9ea8a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.Notification;
@@ -76,7 +75,6 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.RemoteViews;
import android.widget.TextView;
@@ -86,10 +84,10 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.NotificationColorUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SwipeHelper;
@@ -1175,7 +1173,7 @@
}
protected void toggleKeyboardShortcuts() {
- getKeyboardShortcuts().toggleKeyboardShortcuts(mContext);
+ getKeyboardShortcuts().toggleKeyboardShortcuts();
}
protected void cancelPreloadingRecents() {
@@ -1518,7 +1516,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/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index cc26223..60fc0fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,6 +21,7 @@
import android.os.IBinder;
import android.os.Message;
import android.util.Pair;
+
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 24cd948..212d290 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,7 +18,7 @@
import android.view.View;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.Interpolators;
/**
* A helper to fade views in and out.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
index a323684..46060f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
@@ -25,6 +25,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 5c83f5f..b326552 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -27,6 +27,7 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6fae3ab..c68d7d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -28,7 +28,6 @@
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Chronometer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index c4ffd7f..bddd3e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -22,6 +22,8 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.systemui.Interpolators;
+
/**
* Utility class to calculate general fling animation when the finger is released.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index b36fb7e..963920c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -19,25 +19,30 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
import android.os.Handler;
-import android.util.Log;
+import android.os.Looper;
+import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
+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.view.Gravity.TOP;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -45,33 +50,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 +95,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 +102,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/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 841b9d0..0b1984d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -36,6 +36,7 @@
import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardAffordanceHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 635e66d..00b9888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -19,7 +19,6 @@
import android.app.Notification;
import android.app.RemoteInput;
import android.content.Context;
-import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Build;
import android.service.notification.StatusBarNotification;
@@ -27,7 +26,6 @@
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
@@ -53,6 +51,7 @@
private final Rect mClipBounds = new Rect();
private final int mMinContractedHeight;
+ private final int mNotificationContentMarginEnd;
private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -109,6 +108,8 @@
mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
+ mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
reset(true);
}
@@ -128,6 +129,19 @@
maxSize = MeasureSpec.getSize(heightMeasureSpec);
}
int maxChildHeight = 0;
+ if (mExpandedChild != null) {
+ int size = Math.min(maxSize, mNotificationMaxHeight);
+ ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
+ if (layoutParams.height >= 0) {
+ // An actual height is set
+ size = Math.min(maxSize, layoutParams.height);
+ }
+ int spec = size == Integer.MAX_VALUE
+ ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+ : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+ mExpandedChild.measure(widthMeasureSpec, spec);
+ maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
+ }
if (mContractedChild != null) {
int heightSpec;
if (shouldContractedBeFixedSize()) {
@@ -143,19 +157,9 @@
mContractedChild.measure(widthMeasureSpec, heightSpec);
}
maxChildHeight = Math.max(maxChildHeight, measuredHeight);
- }
- if (mExpandedChild != null) {
- int size = Math.min(maxSize, mNotificationMaxHeight);
- ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
- if (layoutParams.height >= 0) {
- // An actual height is set
- size = Math.min(maxSize, layoutParams.height);
+ if (updateContractedHeaderWidth()) {
+ mContractedChild.measure(widthMeasureSpec, heightSpec);
}
- int spec = size == Integer.MAX_VALUE
- ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
- mExpandedChild.measure(widthMeasureSpec, spec);
- maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
}
if (mHeadsUpChild != null) {
int size = Math.min(maxSize, mHeadsUpHeight);
@@ -178,6 +182,44 @@
setMeasuredDimension(width, ownHeight);
}
+ private boolean updateContractedHeaderWidth() {
+ // We need to update the expanded and the collapsed header to have exactly the same with to
+ // have the expand buttons laid out at the same location.
+ NotificationHeaderView contractedHeader = mContractedWrapper.getNotificationHeader();
+ if (contractedHeader != null) {
+ if (mExpandedChild != null
+ && mExpandedWrapper.getNotificationHeader() != null) {
+ NotificationHeaderView expandedHeader = mExpandedWrapper.getNotificationHeader();
+ int expandedSize = expandedHeader.getMeasuredWidth()
+ - expandedHeader.getPaddingEnd();
+ int collapsedSize = contractedHeader.getMeasuredWidth()
+ - expandedHeader.getPaddingEnd();
+ if (expandedSize != collapsedSize) {
+ int paddingEnd = contractedHeader.getMeasuredWidth() - expandedSize;
+ contractedHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : contractedHeader.getPaddingLeft(),
+ contractedHeader.getPaddingTop(),
+ isLayoutRtl() ? contractedHeader.getPaddingLeft() : paddingEnd,
+ contractedHeader.getPaddingBottom());
+ contractedHeader.setShowWorkBadgeAtEnd(true);
+ return true;
+ }
+ } else {
+ int paddingEnd = mNotificationContentMarginEnd;
+ if (contractedHeader.getPaddingEnd() != paddingEnd) {
+ contractedHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : contractedHeader.getPaddingLeft(),
+ contractedHeader.getPaddingTop(),
+ isLayoutRtl() ? contractedHeader.getPaddingLeft() : paddingEnd,
+ contractedHeader.getPaddingBottom());
+ contractedHeader.setShowWorkBadgeAtEnd(false);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private boolean shouldContractedBeFixedSize() {
return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
}
@@ -460,16 +502,16 @@
if (mDark == dark || mContractedChild == null) return;
mDark = dark;
dark = dark && !mShowingLegacyBackground;
- if (mVisibleType == VISIBLE_TYPE_CONTRACTED) {
+ if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
mContractedWrapper.setDark(dark, fade, delay);
}
- if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
+ if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
mExpandedWrapper.setDark(dark, fade, delay);
}
- if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
+ if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
mHeadsUpWrapper.setDark(dark, fade, delay);
}
- if (mSingleLineView != null && mVisibleType == VISIBLE_TYPE_SINGLELINE) {
+ if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
mSingleLineView.setDark(dark, fade, delay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index c836637..0a7ee51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -21,6 +21,8 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
+
/**
* A common base class for all views in the notification stack scroller which don't have a
* background.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5a7cf86..e4accf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -24,15 +24,14 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.graphics.drawable.ScaleDrawable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
+
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index bed64a3..a58fa86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -25,11 +25,13 @@
import android.support.v4.util.SimpleArrayMap;
import android.view.View;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.ActivityStarter;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -62,8 +64,8 @@
private SimpleArrayMap<String, Integer> mFacetPackageMap
= new SimpleArrayMap<String, Integer>();
- private List<Intent> mIntents = new ArrayList<Intent>();
- private List<Intent> mLongPressIntents = new ArrayList<Intent>();
+ private List<Intent> mIntents;
+ private List<Intent> mLongPressIntents;
private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
@@ -112,16 +114,19 @@
throw new RuntimeException("car_facet array lengths do not match");
}
+ mIntents = createEmptyIntentList(icons.length());
+ mLongPressIntents = createEmptyIntentList(icons.length());
+
for (int i = 0; i < icons.length(); i++) {
Drawable icon = icons.getDrawable(i);
try {
- mIntents.add(i,
+ mIntents.set(i,
Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME));
String longpressUri = longpressIntents.getString(i);
boolean hasLongpress = !longpressUri.isEmpty();
if (hasLongpress) {
- mLongPressIntents.add(i,
+ mLongPressIntents.set(i,
Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME));
}
@@ -299,4 +304,8 @@
setCurrentFacet(index);
startActivity(mLongPressIntents.get(index));
}
+
+ private List<Intent> createEmptyIntentList(int size) {
+ return Arrays.asList(new Intent[size]);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index efc3646..d530759 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -17,20 +17,13 @@
package com.android.systemui.statusbar.car;
import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.R.color;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.NavigationBarView;
-import java.util.ArrayList;
-import java.util.HashMap;
-
/**
* A custom navigation bar for the automotive use case.
* <p>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 504f059..59e4244 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -19,6 +19,7 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
+
import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 3025092..8e6c153 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.car;
-import android.content.Context;
-import android.provider.Settings;
import android.view.View;
import android.view.ViewStub;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
index bf291d3..81483c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
@@ -30,6 +30,8 @@
private static Pools.SimplePool<HeaderTransformState> sInstancePool
= new Pools.SimplePool<>(40);
private View mExpandButton;
+ private View mWorkProfileIcon;
+ private TransformState mWorkProfileState;
@Override
public void initFrom(View view) {
@@ -37,13 +39,16 @@
if (view instanceof NotificationHeaderView) {
NotificationHeaderView header = (NotificationHeaderView) view;
mExpandButton = header.getExpandButton();
+ mWorkProfileState = TransformState.obtain();
+ mWorkProfileIcon = header.getWorkProfileIcon();
+ mWorkProfileState.initFrom(mWorkProfileIcon);
}
}
@Override
public boolean transformViewTo(TransformState otherState, Runnable endRunnable) {
// if the transforming notification has a header, we have ensured that it looks the same
- // but the expand button, so lets fade just that one.
+ // but the expand button, so lets fade just that one and transform the work profile icon.
if (!(mTransformedView instanceof NotificationHeaderView)) {
return false;
}
@@ -66,7 +71,7 @@
@Override
public void transformViewFrom(TransformState otherState) {
// if the transforming notification has a header, we have ensured that it looks the same
- // but the expand button, so lets fade just that one.
+ // but the expand button, so lets fade just that one and transform the work profile icon.
if (!(mTransformedView instanceof NotificationHeaderView)) {
return;
}
@@ -79,10 +84,14 @@
if (headerChild.getVisibility() == View.GONE) {
continue;
}
- if (headerChild != mExpandButton) {
- headerChild.setVisibility(View.VISIBLE);
- } else {
+ if (headerChild == mExpandButton) {
CrossFadeHelper.fadeIn(mExpandButton);
+ } else {
+ headerChild.setVisibility(View.VISIBLE);
+ if (headerChild == mWorkProfileIcon) {
+ mWorkProfileState.animateViewFrom(
+ ((HeaderTransformState) otherState).mWorkProfileState);
+ }
}
}
return;
@@ -99,6 +108,9 @@
@Override
public void recycle() {
super.recycle();
+ if (mWorkProfileState != null) {
+ mWorkProfileState.recycle();
+ }
sInstancePool.release(this);
}
@@ -106,6 +118,7 @@
protected void reset() {
super.reset();
mExpandButton = null;
+ mWorkProfileState = null;
}
public void setVisible(boolean visible) {
@@ -125,6 +138,10 @@
if (headerChild == mExpandButton) {
headerChild.setAlpha(visible ? 1.0f : 0.0f);
}
+ if (headerChild == mWorkProfileIcon) {
+ headerChild.setTranslationX(0);
+ headerChild.setTranslationY(0);
+ }
}
}
@@ -144,6 +161,10 @@
headerChild.animate().cancel();
headerChild.setVisibility(View.VISIBLE);
headerChild.setAlpha(1.0f);
+ if (headerChild == mWorkProfileIcon) {
+ headerChild.setTranslationX(0);
+ headerChild.setTranslationY(0);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index 5eed5ed..ec73935 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
@@ -32,8 +31,6 @@
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
-import java.util.ArrayList;
-
/**
* A hybrid view which may contain information about one ore more notifications.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
index ce9540b..c561601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.graphics.drawable.Icon;
import android.os.Bundle;
-import android.os.Parcelable;
import android.service.notification.StatusBarNotification;
import android.view.View;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 97bf4b4..60c1911 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -35,6 +35,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
+ super.setDark(dark, fade, delay);
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index f43a5d0..5a71caf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -28,22 +28,18 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
-import java.util.Collection;
import java.util.Stack;
/**
@@ -95,6 +91,7 @@
@Override
public void notifyContentUpdated(StatusBarNotification notification) {
+ super.notifyContentUpdated(notification);
// Reinspect the notification.
resolveHeaderViews();
updateInvertHelper();
@@ -150,6 +147,10 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
+ super.setDark(dark, fade, delay);
if (fade) {
mInvertHelper.fade(dark, delay);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 3475d13..b060245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -25,8 +25,8 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -172,6 +172,9 @@
@Override
public void setDark(boolean dark, boolean fade, long delay) {
+ if (dark == mDark) {
+ return;
+ }
super.setDark(dark, fade, delay);
setPictureGrayscale(dark, fade, delay);
setProgressBarDark(dark, fade, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index c931800..7089b78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,12 +16,10 @@
package com.android.systemui.statusbar.notification;
-import android.view.View;
import android.widget.ImageView;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarIconView;
/**
* A util class for various reusable functions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index a1cf07e..f50b976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -31,6 +31,7 @@
public abstract class NotificationViewWrapper implements TransformableView {
protected final View mView;
+ protected boolean mDark;
public static NotificationViewWrapper wrap(Context ctx, View v) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -56,13 +57,17 @@
* @param fade whether to animate the transition if the mode changes
* @param delay if fading, the delay of the animation
*/
- public abstract void setDark(boolean dark, boolean fade, long delay);
+ public void setDark(boolean dark, boolean fade, long delay) {
+ mDark = dark;
+ }
/**
* Notifies this wrapper that the content of the view might have changed.
* @param notification
*/
- public void notifyContentUpdated(StatusBarNotification notification) {};
+ public void notifyContentUpdated(StatusBarNotification notification) {
+ mDark = false;
+ };
/**
* Update the appearance of the expand button.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 3e1c40a..5832d86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -26,10 +26,10 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
@@ -286,6 +286,9 @@
}
public void setVisible(boolean visible) {
+ if (mTransformedView.getVisibility() == View.GONE) {
+ return;
+ }
mTransformedView.animate().cancel();
mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 37e5558..5796edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
@@ -29,10 +28,9 @@
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
-import android.view.animation.LinearInterpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class BarTransitions {
private static final boolean DEBUG = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
index 497f044..9a94d34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
+
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index aea9e1e..30d24ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,12 +14,12 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
-
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index b5dba18..7d4515e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -25,9 +25,9 @@
import android.util.Log;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
-import com.android.systemui.statusbar.Interpolators;
/**
* Controller which handles all the doze animations of the scrims.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index e7064e5..b5b7f43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -21,7 +21,6 @@
import android.view.ViewConfiguration;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.policy.HeadsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index c220efe..915b565 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -25,10 +25,10 @@
import android.view.View;
import android.view.ViewConfiguration;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 94d3829..83a15ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -45,8 +45,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -55,10 +53,10 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index e67aa84..7fbb176 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -28,8 +28,8 @@
import android.widget.TextView;
import com.android.systemui.BatteryMeterView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 8717a15..03dd25e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -66,6 +66,9 @@
}
public boolean hasMultipleUsers() {
+ if (mUserListener == null) {
+ return false;
+ }
return mUserListener.getCount() != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 786e64d..a2586f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -28,13 +28,15 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.tuner.TunerService;
-import static android.view.WindowManager.*;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_TOP;
/**
* Class to detect gestures on the navigation bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 6cfd715..9359301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -18,10 +18,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.drawable.Icon;
-import android.net.Uri;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -30,11 +27,11 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.tuner.TunerService;
-import java.io.File;
import java.util.Objects;
public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index d86629f..5f5974e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,7 +21,6 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.annotation.Nullable;
import android.app.ActivityManagerNative;
import android.app.StatusBarManager;
import android.content.Context;
@@ -47,6 +46,7 @@
import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
+
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 405ef05..03a597c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -8,6 +8,7 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
+
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 8e89efd..277668f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -49,6 +49,7 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.qs.QSContainer;
@@ -57,7 +58,6 @@
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f036d04..c9bb15d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -34,11 +34,11 @@
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.HeadsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index a6ebab3..0a03a98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -105,6 +105,7 @@
import com.android.systemui.DemoMode;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
+import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
@@ -114,8 +115,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
@@ -126,7 +125,6 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 37d61b9..df5a622 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -34,6 +34,7 @@
import android.provider.Settings.Global;
import android.telecom.TelecomManager;
import android.util.Log;
+
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index b8cd7fb..8e2d828 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -28,6 +28,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.external.CustomTile;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index f18c341..9aeb1f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -31,6 +31,7 @@
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
+
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 7247b57..6220fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -28,7 +28,7 @@
import android.view.animation.AnimationUtils;
import com.android.keyguard.AlphaOptimizedImageButton;
-import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.Interpolators;
public class SettingsButton extends AlphaOptimizedImageButton {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index c6537e8..9996b75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -39,8 +39,8 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.FontSizeUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 382de19..fcaf050 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -24,7 +24,6 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
import android.view.WindowManager;
import com.android.keyguard.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 35a17e4..eb5b57e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -30,7 +30,6 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 116237d..0442ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -16,12 +16,12 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.R;
-
import android.app.AlertDialog;
import android.content.Context;
import android.view.WindowManager;
+import com.android.systemui.R;
+
/**
* Base class for dialogs that should appear over panels and keyguard.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
index 1aae496..d5a91bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
@@ -31,8 +31,8 @@
import android.graphics.drawable.Drawable;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
public class TrustDrawable extends Drawable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index fd3c96e..093a827 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -16,23 +16,22 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
+import com.android.systemui.R;
+
/**
* A view that displays a user image cropped to a circle with a frame.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 8fa9c7e..e7e2ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -33,6 +33,7 @@
Collection<CachedBluetoothDevice> getDevices();
void connect(CachedBluetoothDevice device);
void disconnect(CachedBluetoothDevice device);
+ boolean canConfigBluetooth();
public interface Callback {
void onBluetoothStateChange(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index a04edf7..6439bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,11 +16,14 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -39,6 +42,8 @@
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final LocalBluetoothManager mLocalBluetoothManager;
+ private final UserManager mUserManager;
+ private final int mCurrentUser;
private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
@@ -54,6 +59,14 @@
onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
}
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
+ }
+
+ @Override
+ public boolean canConfigBluetooth() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
+ UserHandle.of(mCurrentUser));
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 59d54ff..3bd68a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -20,8 +20,8 @@
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index e344954..b89a77b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
-
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -41,6 +39,8 @@
import java.util.Set;
import java.util.UUID;
+import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+
/** Platform implementation of the cast controller. **/
public class CastControllerImpl implements CastController {
private static final String TAG = "CastController";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 7054bb8..3293964 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import libcore.icu.LocaleData;
+
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -36,12 +38,12 @@
import android.view.Display;
import android.view.View;
import android.widget.TextView;
+
import com.android.systemui.DemoMode;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import libcore.icu.LocaleData;
import java.text.SimpleDateFormat;
import java.util.Calendar;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
index e5d244f..d47050c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
@@ -14,15 +14,17 @@
package com.android.systemui.statusbar.policy;
+import libcore.util.Objects;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.provider.Settings;
+
import com.android.systemui.R;
import com.android.systemui.tuner.TunerService;
-import libcore.util.Objects;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 7ca91a5..b036936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,6 +22,7 @@
boolean isHotspotEnabled();
boolean isHotspotSupported();
void setHotspotEnabled(boolean enabled);
+ boolean isTetheringAllowed();
public interface Callback {
void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 5719f76..61d26c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,12 +16,15 @@
package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import com.android.settingslib.TetherUtil;
@@ -39,13 +42,17 @@
private final Receiver mReceiver = new Receiver();
private final ConnectivityManager mConnectivityManager;
private final Context mContext;
+ private final UserManager mUserManager;
+ private final int mCurrentUser;
private int mHotspotState;
public HotspotControllerImpl(Context context) {
mContext = context;
- mConnectivityManager = (ConnectivityManager)context.getSystemService(
+ mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,6 +102,12 @@
return TetherUtil.isTetheringSupported(mContext);
}
+ @Override
+ public boolean isTetheringAllowed() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
+ UserHandle.of(mCurrentUser));
+ }
+
static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index d739d6c1..57e092a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -31,8 +31,8 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.Interpolators;
import java.util.ArrayList;
import java.util.HashSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 6e7cf19..c8c824a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -24,7 +24,6 @@
import android.graphics.drawable.Icon;
import android.hardware.input.InputManager;
import android.media.AudioManager;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index cec0c0a..970fed0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.os.RemoteException;
import android.view.WindowManagerGlobal;
+
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.settings.CurrentUserTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 0959b0c..867a8a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,20 +21,18 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
-import android.graphics.Interpolator;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
-import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.qs.tiles.UserDetailItemView;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..401943e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,6 +21,7 @@
boolean setLocationEnabled(boolean enabled);
void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
+ boolean isUserLocationRestricted();
/**
* A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 7517f97..436a40d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,6 +52,7 @@
private AppOpsManager mAppOpsManager;
private StatusBarManager mStatusBarManager;
+ private final int mCurrentUser;
private boolean mAreActiveLocationRequests;
@@ -73,6 +74,7 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mStatusBarManager
= (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+ mCurrentUser = ActivityManager.getCurrentUser();
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -103,10 +105,6 @@
* @return true if attempt to change setting was successful.
*/
public boolean setLocationEnabled(boolean enabled) {
- int currentUserId = ActivityManager.getCurrentUser();
- if (isUserLocationRestricted(currentUserId)) {
- return false;
- }
final ContentResolver cr = mContext.getContentResolver();
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
@@ -115,7 +113,7 @@
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+ .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
}
/**
@@ -133,11 +131,10 @@
/**
* Returns true if the current user is restricted from using location.
*/
- private boolean isUserLocationRestricted(int userId) {
+ public boolean isUserLocationRestricted() {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- return um.hasUserRestriction(
- UserManager.DISALLOW_SHARE_LOCATION,
- new UserHandle(userId));
+ return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+ UserHandle.of(mCurrentUser));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 755a5b3..93c7322 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
import android.telephony.SubscriptionInfo;
+
import com.android.settingslib.net.DataUsageController;
import com.android.settingslib.wifi.AccessPoint;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 107a904..eecf8c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -37,6 +37,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 61a9851..c6659d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -16,12 +16,6 @@
package com.android.systemui.statusbar.policy;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.NotificationData;
-import com.android.systemui.statusbar.RemoteInputController;
-
-import android.annotation.NonNull;
-import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
@@ -47,7 +41,9 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import java.util.ArrayList;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.RemoteInputController;
/**
* Host for the remote input.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6ddd7a3..a85fe0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -25,21 +25,17 @@
import android.net.IConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
import android.net.NetworkRequest;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
import com.android.systemui.R;
import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index 5e9447e..c954d08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG;
-
import android.content.Context;
import android.text.format.DateFormat;
import android.util.Log;
@@ -24,6 +22,8 @@
import java.io.PrintWriter;
import java.util.BitSet;
+import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG;
+
/**
* Common base class for handling signal for both wifi and mobile data.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index 6931d1e..85ac755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -36,9 +36,9 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.util.UserIcons;
import com.android.systemui.BitmapHelper;
import com.android.systemui.R;
-import com.android.internal.util.UserIcons;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e4ded67..6ca7dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -22,9 +22,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -34,8 +32,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -44,7 +40,6 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
@@ -622,7 +617,7 @@
private void checkIfAddUserDisallowed(UserRecord record) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
- UserManager.DISALLOW_ADD_USER, UserHandle.myUserId());
+ UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
if (admin != null) {
record.isDisabledByAdmin = true;
record.enforcedAdmin = admin;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index eab6e13..cc98eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -23,6 +23,7 @@
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.settingslib.wifi.WifiStatusTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index a3f571e..50e5b88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -19,7 +19,6 @@
import android.view.View;
import com.android.systemui.statusbar.ActivatableNotificationView;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 60dca99..d6276b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -46,6 +46,7 @@
import android.widget.OverScroller;
import com.android.systemui.ExpandHelper;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.classifier.FalsingManager;
@@ -54,7 +55,6 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index e75e8e8..cf4802d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -24,10 +24,10 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
index 41824ea..05fa27d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -16,10 +16,6 @@
package com.android.systemui.statusbar.stack;
-import android.view.View;
-
-import com.android.systemui.statusbar.ExpandableView;
-
/**
* A state of an expandable view
*/
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
index 63ed912..919f150 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
@@ -14,8 +14,6 @@
package com.android.systemui.tuner;
-import com.android.systemui.R;
-
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ClipboardManager.OnPrimaryClipChangedListener;
@@ -26,6 +24,8 @@
import android.view.View;
import android.widget.ImageView;
+import com.android.systemui.R;
+
public class ClipboardView extends ImageView implements OnPrimaryClipChangedListener {
private static final int TARGET_COLOR = 0x4dffffff;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
index 1933c15..7b06393 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
@@ -17,6 +17,7 @@
import android.app.ActivityManager;
import android.provider.Settings;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
index e6073ae..096ecc0 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
@@ -18,14 +18,13 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.net.Uri;
-import android.util.Pair;
import android.view.KeyEvent;
+import com.android.systemui.R;
+
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
-import com.android.systemui.R;
public class KeycodeSelectionHelper {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 6fba9dc..5ded885 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -14,8 +14,6 @@
package com.android.systemui.tuner;
-import com.android.systemui.R;
-
import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlertDialog;
@@ -34,7 +32,6 @@
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
-import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.LayoutInflater;
@@ -49,26 +46,28 @@
import android.widget.SeekBar;
import android.widget.TextView;
+import com.android.systemui.R;
+
import java.util.ArrayList;
import java.util.List;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BACK;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BUTTON_SEPARATOR;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.CLIPBOARD;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.GRAVITY_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.HOME;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_END;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_START;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractSize;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BACK;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BUTTON_SEPARATOR;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.GRAVITY_SEPARATOR;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.HOME;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.RECENT;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractSize;
public class NavBarTuner extends Fragment implements TunerService.Tunable {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
index b30ca5c..e6e8f4e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
@@ -14,12 +14,12 @@
package com.android.systemui.tuner;
-import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
-
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
+
public class PreviewNavInflater extends NavigationBarInflaterView {
public PreviewNavInflater(Context context, AttributeSet attrs) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index e4d7be7..9df5368 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -18,7 +18,6 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
-import android.app.FragmentTransaction;
import android.content.DialogInterface;
import android.database.ContentObserver;
import android.net.Uri;
@@ -30,7 +29,6 @@
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index abaa628..f298e16 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -33,6 +33,7 @@
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index e947ed5..f4a8873 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.tv.pip;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
@@ -37,8 +38,6 @@
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import android.app.ActivityManager.RunningTaskInfo;
-
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 97c70ed..15c55f5 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.media.session.MediaController;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index de997a8..bc59a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
-import android.util.Log;
import android.view.View;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index 0979ffd..bafd1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -22,12 +22,9 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.UserInfo;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 5dc468b..6aae9bd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -16,9 +16,6 @@
package com.android.systemui.volume;
-import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
-import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
-
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.LayoutTransition;
import android.animation.ValueAnimator;
@@ -77,6 +74,9 @@
import java.util.ArrayList;
import java.util.List;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
/**
* Visual presentation of the volume dialog.
*
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 673a30b..99c0f59 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -41,7 +41,6 @@
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.Condition;
-import android.service.notification.ZenModeConfig;
import android.util.Log;
import android.util.SparseArray;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index b7a41e2..964688b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,12 +17,15 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_JACK_FLAGS := --multi-dex native
+
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview
+ --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview \
+ --extra-packages android.support.v17.leanback
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
@@ -35,6 +38,7 @@
frameworks/support/v14/preference/res \
frameworks/support/v7/appcompat/res \
frameworks/support/v7/recyclerview/res \
+ frameworks/support/v17/leanback/res \
frameworks/base/packages/SystemUI/res \
frameworks/base/packages/Keyguard/res
@@ -48,7 +52,8 @@
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference
+ android-support-v14-preference \
+ android-support-v17-leanback
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 03809c0..53504cc 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;
}
@@ -954,7 +958,15 @@
final UserState state = getCurrentUserStateLocked();
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
final Service service = state.mBoundServices.get(i);
- service.notifyMagnificationChanged(region, scale, centerX, centerY);
+ service.notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+ }
+ }
+
+ private void notifySoftKeyboardShowModeChangedLocked(int showMode) {
+ final UserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ final Service service = state.mBoundServices.get(i);
+ service.notifySoftKeyboardShowModeChangedLocked(showMode);
}
}
@@ -1027,6 +1039,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;
}
@@ -1400,6 +1415,7 @@
updateEnhancedWebAccessibilityLocked(userState);
updateDisplayColorAdjustmentSettingsLocked(userState);
updateMagnificationLocked(userState);
+ updateSoftKeyboardShowModeLocked(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
}
@@ -1616,6 +1632,18 @@
return false;
}
+ private boolean readSoftKeyboardShowModeChangedLocked(UserState userState) {
+ final int softKeyboardShowMode = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0,
+ userState.mUserId);
+ if (softKeyboardShowMode != userState.mSoftKeyboardShowMode) {
+ userState.mSoftKeyboardShowMode = softKeyboardShowMode;
+ return true;
+ }
+ return false;
+ }
+
private void updateTouchExplorationLocked(UserState userState) {
boolean enabled = false;
final int serviceCount = userState.mBoundServices.size();
@@ -1750,6 +1778,25 @@
return false;
}
+ private void updateSoftKeyboardShowModeLocked(UserState userState) {
+ final int userId = userState.mUserId;
+ if (userId == mCurrentUserId) {
+ // Check whether any Accessibility Services are still enabled and, if not, remove flag
+ // requesting no soft keyboard
+ final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
+ if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
+ // No active Accessibility Services can be requesting the soft keyboard to be hidden
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0,
+ userState.mUserId);
+ userState.mSoftKeyboardShowMode = 0;
+ }
+
+ notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
+ }
+ }
+
private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
IBinder windowToken = mGlobalWindowTokens.get(windowId);
if (windowToken == null) {
@@ -2095,7 +2142,7 @@
};
// Handler for scheduling method invocations on the main thread.
- public InvocationHandler mInvocationHandler = new InvocationHandler(
+ public final InvocationHandler mInvocationHandler = new InvocationHandler(
mMainHandler.getLooper());
public Service(int userId, ComponentName componentName,
@@ -2290,17 +2337,20 @@
}
}
+ private boolean isCalledForCurrentUserLocked() {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
+ final int resolvedUserId = mSecurityPolicy
+ .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT);
+ return resolvedUserId == mCurrentUserId;
+ }
+
@Override
public List<AccessibilityWindowInfo> getWindows() {
ensureWindowsAvailableTimed();
synchronized (mLock) {
- // We treat calls from a profile as if made by its perent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return null;
}
final boolean permissionGranted =
@@ -2328,13 +2378,7 @@
public AccessibilityWindowInfo getWindow(int windowId) {
ensureWindowsAvailableTimed();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return null;
}
final boolean permissionGranted =
@@ -2361,13 +2405,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2418,13 +2456,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2475,13 +2507,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2532,13 +2558,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
@@ -2590,13 +2610,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2663,13 +2677,7 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2702,13 +2710,7 @@
@Override
public boolean performGlobalAction(int action) {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
}
@@ -2743,13 +2745,7 @@
@Override
public float getMagnificationScale() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 1.0f;
}
}
@@ -2764,13 +2760,7 @@
@Override
public Region getMagnifiedRegion() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return Region.obtain();
}
}
@@ -2787,13 +2777,7 @@
@Override
public float getMagnificationCenterX() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 0.0f;
}
}
@@ -2808,13 +2792,7 @@
@Override
public float getMagnificationCenterY() {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 0.0f;
}
}
@@ -2829,13 +2807,7 @@
@Override
public boolean resetMagnification(boolean animate) {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2855,13 +2827,7 @@
public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
boolean animate) {
synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2884,6 +2850,33 @@
}
@Override
+ public boolean setSoftKeyboardShowMode(int showMode) {
+ final UserState userState;
+ synchronized (mLock) {
+ if (!isCalledForCurrentUserLocked()) {
+ return false;
+ }
+
+ userState = getCurrentUserStateLocked();
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode,
+ userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return true;
+ }
+
+ @Override
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
synchronized (mLock) {
@@ -3073,9 +3066,14 @@
InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
}
- public void notifyMagnificationChanged(@NonNull Region region,
+ public void notifyMagnificationChangedLocked(@NonNull Region region,
float scale, float centerX, float centerY) {
- mInvocationHandler.notifyMagnificationChanged(region, scale, centerX, centerY);
+ mInvocationHandler
+ .notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+ }
+
+ public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+ mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
}
/**
@@ -3097,6 +3095,25 @@
}
}
+ /**
+ * Called by the invocation handler to notify the service that the state of the soft
+ * keyboard show mode has changed.
+ */
+ private void notifySoftKeyboardShowModeChangedInternal(int showState) {
+ final IAccessibilityServiceClient listener;
+ synchronized (mLock) {
+ listener = mServiceInterface;
+ }
+ if (listener != null) {
+ try {
+ listener.onSoftKeyboardShowModeChanged(showState);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
+ re);
+ }
+ }
+ }
+
private void notifyGestureInternal(int gestureId) {
final IAccessibilityServiceClient listener;
synchronized (mLock) {
@@ -3232,8 +3249,10 @@
public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
+ private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
private boolean mIsMagnificationCallbackEnabled = false;
+ private boolean mIsSoftKeyboardCallbackEnabled = false;
public InvocationHandler(Looper looper) {
super(looper, null, true);
@@ -3261,13 +3280,18 @@
notifyMagnificationChangedInternal(region, scale, centerX, centerY);
} break;
+ case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
+ final int showState = (int) message.arg1;
+ notifySoftKeyboardShowModeChangedInternal(showState);
+ } break;
+
default: {
throw new IllegalArgumentException("Unknown message: " + type);
}
}
}
- public void notifyMagnificationChanged(@NonNull Region region, float scale,
+ public void notifyMagnificationChangedLocked(@NonNull Region region, float scale,
float centerX, float centerY) {
if (!mIsMagnificationCallbackEnabled) {
// Callback is disabled, don't bother packing args.
@@ -3287,8 +3311,20 @@
public void setMagnificationCallbackEnabled(boolean enabled) {
mIsMagnificationCallbackEnabled = enabled;
}
- }
+ public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+ if (!mIsSoftKeyboardCallbackEnabled) {
+ return;
+ }
+
+ final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
+ msg.sendToTarget();
+ }
+
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ mIsSoftKeyboardCallbackEnabled = enabled;
+ }
+ }
}
final class WindowsForAccessibilityCallback implements
@@ -3969,6 +4005,8 @@
public int mLastSentClientState = -1;
+ public int mSoftKeyboardShowMode = 0;
+
public boolean mIsAccessibilityEnabled;
public boolean mIsTouchExplorationEnabled;
public boolean mIsTextHighContrastEnabled;
@@ -3981,6 +4019,7 @@
public boolean mAccessibilityFocusOnlyInActiveWindow;
private Service mUiAutomationService;
+ private int mUiAutomationFlags;
private IAccessibilityServiceClient mUiAutomationServiceClient;
private IBinder mUiAutomationServiceOwner;
@@ -4040,10 +4079,12 @@
mIsEnhancedWebAccessibilityEnabled = false;
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
+ mSoftKeyboardShowMode = 0;
}
public void destroyUiAutomationService() {
mUiAutomationService = null;
+ mUiAutomationFlags = 0;
mUiAutomationServiceClient = null;
if (mUiAutomationServiceOwner != null) {
mUiAutomationServiceOwner.unlinkToDeath(
@@ -4051,6 +4092,11 @@
mUiAutomationServiceOwner = null;
}
}
+
+ boolean isUiAutomationSuppressingOtherServices() {
+ return ((mUiAutomationService != null) && (mUiAutomationFlags
+ & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0);
+ }
}
private final class AccessibilityContentObserver extends ContentObserver {
@@ -4091,6 +4137,9 @@
private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
+ private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+
public AccessibilityContentObserver(Handler handler) {
super(handler);
}
@@ -4121,6 +4170,8 @@
mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mHighTextContrastUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -4130,8 +4181,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;
}
@@ -4175,6 +4226,10 @@
if (readHighTextContrastEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
}
+ } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) {
+ if (readSoftKeyboardShowModeChangedLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 666f2ff..aaa2211 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -12,4 +12,9 @@
LOCAL_JAVA_LIBRARIES := services.net telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+ifneq ($(INCREMENTAL_BUILDS),)
+ LOCAL_PROGUARD_ENABLED := disabled
+ LOCAL_JACK_ENABLED := incremental
+endif
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2d1f96b..3fd8b40 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -33,7 +33,6 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.annotation.Nullable;
-import android.app.AlarmManager;
import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
@@ -88,7 +87,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -115,7 +113,6 @@
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
-import com.android.internal.telephony.DctConstants;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
@@ -155,11 +152,9 @@
import java.util.HashSet;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* @hide
@@ -2186,7 +2181,7 @@
if (wasDefault) {
mDefaultInetConditionPublished = 0;
}
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
// by other networks that are already connected. Perhaps that can be done by
// sending all CALLBACK_LOST messages (for requests, not listens) at the end
@@ -4095,7 +4090,7 @@
}
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -4719,7 +4714,11 @@
notifyLockdownVpn(networkAgent);
if (oldInfo != null && oldInfo.getState() == state) {
- if (VDBG) log("ignoring duplicate network state non-change");
+ if (oldInfo.isRoaming() != newInfo.isRoaming()) {
+ if (VDBG) log("roaming status changed, notifying NetworkStatsService");
+ notifyIfacesChangedForNetworkStats();
+ } else if (VDBG) log("ignoring duplicate network state non-change");
+ // In either case, no further work should be needed.
return;
}
if (DBG) {
@@ -4749,7 +4748,7 @@
}
networkAgent.created = true;
updateLinkProperties(networkAgent, null);
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
scheduleUnvalidatedPrompt(networkAgent);
@@ -4913,9 +4912,10 @@
}
/**
- * Notify other system services that set of active ifaces has changed.
+ * Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
+ * properties tracked by NetworkStatsService on an active iface has changed.
*/
- private void notifyIfacesChanged() {
+ private void notifyIfacesChangedForNetworkStats() {
try {
mStatsService.forceUpdateIfaces();
} catch (Exception ignored) {
@@ -4949,7 +4949,7 @@
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
if (success) {
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
}
return success;
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4a123df..d77def6 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -448,6 +448,7 @@
private int[] mSubtypeIds;
private Locale mLastSystemLocale;
private boolean mShowImeWithHardKeyboard;
+ private boolean mAccessibilityRequestingNoSoftKeyboard;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final IPackageManager mIPackageManager;
private final String mSlotIme;
@@ -485,15 +486,31 @@
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
mRegistered = true;
}
@Override public void onChange(boolean selfChange, Uri uri) {
- final Uri showImeUri =
- Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ final Uri showImeUri = Settings.Secure.getUriFor(
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
synchronized (mMethodMap) {
if (showImeUri.equals(uri)) {
updateKeyboardFromSettingsLocked();
+ } else if (accessibilityRequestingNoImeUri.equals(uri)) {
+ mAccessibilityRequestingNoSoftKeyboard = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0, mUserId) == 1;
+ if (mAccessibilityRequestingNoSoftKeyboard) {
+ final boolean showRequested = mShowRequested;
+ hideCurrentInputLocked(0, null);
+ mShowRequested = showRequested;
+ } else if (mShowRequested) {
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ }
} else {
boolean enabledChanged = false;
String newEnabled = mSettings.getEnabledInputMethodsStr();
@@ -655,7 +672,7 @@
boolean changed = false;
if (curIm != null) {
- int change = isPackageDisappearing(curIm.getPackageName());
+ int change = isPackageDisappearing(curIm.getPackageName());
if (change == PACKAGE_TEMPORARY_CHANGE
|| change == PACKAGE_PERMANENT_CHANGE) {
ServiceInfo si = null;
@@ -2073,12 +2090,15 @@
boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
mShowRequested = true;
- if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
- mShowExplicitlyRequested = true;
+ if (mAccessibilityRequestingNoSoftKeyboard) {
+ return false;
}
+
if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
mShowExplicitlyRequested = true;
mShowForced = true;
+ } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
+ mShowExplicitlyRequested = true;
}
if (!mSystemReady) {
@@ -3265,7 +3285,7 @@
"Requires permission "
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
-
+
long ident = Binder.clearCallingIdentity();
try {
return setInputMethodEnabledLocked(id, enabled);
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/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 76fbebf..7dd93d8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12970,6 +12970,11 @@
final StringBuilder sb = new StringBuilder(1024);
appendDropBoxProcessHeaders(process, processName, sb);
+ if (process != null) {
+ sb.append("Foreground: ")
+ .append(process.isInterestingToUserLocked() ? "Yes" : "No")
+ .append("\n");
+ }
if (activity != null) {
sb.append("Activity: ").append(activity.shortComponentName).append("\n");
}
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/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index cf876ee..5d97afa 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -189,10 +189,6 @@
mInstaller.execute("freecache", uuid, freeStorageSize);
}
- public void moveFiles() throws InstallerException {
- mInstaller.execute("movefiles");
- }
-
/**
* Links the 32 bit native library directory in an application's data
* directory to the real location for backward compatibility. Note that no
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c3f20eb..1c4176a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2175,13 +2175,6 @@
scanDirTracedLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
- if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- try {
- mInstaller.moveFiles();
- } catch (InstallerException e) {
- logCriticalInfo(Log.WARN, "Update commands failed: " + e);
- }
-
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0f614ca..4ff7667 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -930,6 +930,7 @@
/** @return a specific user restriction that's in effect currently. */
@Override
public boolean hasUserRestriction(String restrictionKey, int userId) {
+ UserRestrictionsUtils.checkRestriction(restrictionKey);
Bundle restrictions = getEffectiveUserRestrictions(userId);
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
@@ -946,6 +947,7 @@
@Override
public boolean hasBaseUserRestriction(String restrictionKey, int userId) {
checkManageUsersPermission("hasBaseUserRestriction");
+ UserRestrictionsUtils.checkRestriction(restrictionKey);
synchronized (mRestrictionsLock) {
Bundle bundle = mBaseUserRestrictions.get(userId);
return (bundle != null && bundle.getBoolean(restrictionKey, false));
@@ -955,6 +957,7 @@
@Override
public void setUserRestriction(String key, boolean value, int userId) {
checkManageUsersPermission("setUserRestriction");
+ UserRestrictionsUtils.checkRestriction(key);
synchronized (mRestrictionsLock) {
// Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create
// a copy.
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 87f505d..7ab071f 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -56,7 +56,15 @@
private UserRestrictionsUtils() {
}
- public static final Set<String> USER_RESTRICTIONS = Sets.newArraySet(
+ private static Set<String> newSetWithUniqueCheck(String[] strings) {
+ final Set<String> ret = Sets.newArraySet(strings);
+
+ // Make sure there's no overlap.
+ Preconditions.checkState(ret.size() == strings.length);
+ return ret;
+ }
+
+ public static final Set<String> USER_RESTRICTIONS = newSetWithUniqueCheck(new String[] {
UserManager.DISALLOW_CONFIG_WIFI,
UserManager.DISALLOW_MODIFY_ACCOUNTS,
UserManager.DISALLOW_INSTALL_APPS,
@@ -94,7 +102,7 @@
UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_DATA_ROAMING,
UserManager.DISALLOW_SET_USER_ICON
- );
+ });
/**
* Set of user restriction which we don't want to persist.
@@ -140,6 +148,15 @@
UserManager.DISALLOW_UNMUTE_MICROPHONE
);
+ /**
+ * Throws {@link IllegalArgumentException} if the given restriction name is invalid.
+ */
+ public static void checkRestriction(@NonNull String restriction) {
+ if (!USER_RESTRICTIONS.contains(restriction)) {
+ throw new IllegalArgumentException("Unknown restriction: " + restriction);
+ }
+ }
+
public static void writeRestrictions(@NonNull XmlSerializer serializer,
@Nullable Bundle restrictions, @NonNull String tag) throws IOException {
if (restrictions == null) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 578428b..4e96d71 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -266,7 +266,7 @@
return (configs.length > 0) ? INPUT_STATE_CONNECTED_STANDBY : INPUT_STATE_DISCONNECTED;
}
- public void addHardwareTvInput(int deviceId, TvInputInfo info) {
+ public void addHardwareInput(int deviceId, TvInputInfo info) {
synchronized (mLock) {
String oldInputId = mHardwareInputIdMap.get(deviceId);
if (oldInputId != null) {
@@ -325,7 +325,7 @@
return false;
}
- public void addHdmiTvInput(int id, TvInputInfo info) {
+ public void addHdmiInput(int id, TvInputInfo info) {
if (info.getType() != TvInputInfo.TYPE_HDMI) {
throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
}
@@ -346,7 +346,7 @@
}
}
- public void removeTvInput(String inputId) {
+ public void removeHardwareInput(String inputId) {
synchronized (mLock) {
mInputMap.remove(inputId);
int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 62e7fb4..b065e85 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;
@@ -310,7 +311,7 @@
userState.serviceStateMap.put(component, serviceState);
updateServiceConnectionLocked(component, userId);
} else {
- inputList.addAll(serviceState.inputList);
+ inputList.addAll(serviceState.hardwareInputList);
}
} else {
try {
@@ -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(),
@@ -1988,7 +2018,7 @@
private final ServiceConnection connection;
private final ComponentName component;
private final boolean isHardware;
- private final List<TvInputInfo> inputList = new ArrayList<>();
+ private final List<TvInputInfo> hardwareInputList = new ArrayList<>();
private ITvInputService service;
private ServiceCallback callback;
@@ -2185,39 +2215,36 @@
}
}
- private void addTvInputLocked(TvInputInfo inputInfo) {
+ private void addHardwareInputLocked(TvInputInfo inputInfo) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
- serviceState.inputList.add(inputInfo);
+ serviceState.hardwareInputList.add(inputInfo);
buildTvInputListLocked(mUserId, null);
}
- @Override
- public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
+ public void addHardwareInput(int deviceId, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
- addTvInputLocked(inputInfo);
+ mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
+ addHardwareInputLocked(inputInfo);
}
}
- @Override
- public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
+ public void addHdmiInput(int id, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
- addTvInputLocked(inputInfo);
+ mTvInputHardwareManager.addHdmiInput(id, inputInfo);
+ addHardwareInputLocked(inputInfo);
}
}
- @Override
- public void removeTvInput(String inputId) {
+ public void removeHardwareInput(String inputId) {
ensureHardwarePermission();
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
boolean removed = false;
- for (Iterator<TvInputInfo> it = serviceState.inputList.iterator();
+ for (Iterator<TvInputInfo> it = serviceState.hardwareInputList.iterator();
it.hasNext(); ) {
if (it.next().getId().equals(inputId)) {
it.remove();
@@ -2227,24 +2254,12 @@
}
if (removed) {
buildTvInputListLocked(mUserId, null);
- mTvInputHardwareManager.removeTvInput(inputId);
+ mTvInputHardwareManager.removeHardwareInput(inputId);
} else {
Slog.e(TAG, "failed to remove input " + inputId);
}
}
}
-
- @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/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 39983dd..c7d7096 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -42,6 +42,9 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -71,6 +74,7 @@
import android.view.IWindowManager;
import android.view.WindowManager;
+import java.io.BufferedOutputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -96,7 +100,7 @@
public class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperManagerService";
- static final boolean DEBUG = false;
+ static final boolean DEBUG = true;
final Object mLock = new Object[0];
@@ -106,7 +110,8 @@
*/
static final long MIN_WALLPAPER_CRASH_TIME = 10000;
static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
- static final String WALLPAPER = "wallpaper";
+ static final String WALLPAPER = "wallpaper_orig";
+ static final String WALLPAPER_CROP = "wallpaper";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
/**
@@ -120,6 +125,7 @@
final WallpaperData mWallpaper;
final File mWallpaperDir;
final File mWallpaperFile;
+ final File mWallpaperCropFile;
final File mWallpaperInfoFile;
public WallpaperObserver(WallpaperData wallpaper) {
@@ -128,6 +134,7 @@
mWallpaperDir = getWallpaperDir(wallpaper.userId);
mWallpaper = wallpaper;
mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+ mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP);
mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
}
@@ -136,8 +143,10 @@
if (path == null) {
return;
}
+ final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+ final File changedFile = new File(mWallpaperDir, path);
+
synchronized (mLock) {
- File changedFile = new File(mWallpaperDir, path);
if (mWallpaperFile.equals(changedFile)
|| mWallpaperInfoFile.equals(changedFile)) {
// changing the wallpaper means we'll need to back up the new one
@@ -148,22 +157,111 @@
}
if (mWallpaperFile.equals(changedFile)) {
notifyCallbacksLocked(mWallpaper);
- final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
if (mWallpaper.wallpaperComponent == null
|| event != CLOSE_WRITE // includes the MOVED_TO case
|| mWallpaper.imageWallpaperPending) {
if (written) {
+ // The image source has finished writing the source image,
+ // so we now produce the crop rect (in the background), and
+ // only publish the new displayable (sub)image as a result
+ // of that work.
+ generateCrop(mWallpaper);
mWallpaper.imageWallpaperPending = false;
+ if (mWallpaper.setComplete != null) {
+ try {
+ mWallpaper.setComplete.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // if this fails we don't really care; the setting app may just
+ // have crashed and that sort of thing is a fact of life.
+ }
+ }
+ bindWallpaperComponentLocked(mImageWallpaper, true,
+ false, mWallpaper, null);
+ saveSettingsLocked(mWallpaper);
}
- bindWallpaperComponentLocked(mImageWallpaper, true,
- false, mWallpaper, null);
- saveSettingsLocked(mWallpaper);
}
}
}
}
}
+ /**
+ * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
+ * for display.
+ */
+ private void generateCrop(WallpaperData wallpaper) {
+ boolean success = false;
+ boolean needCrop = false;
+
+ // Analyse the source; needed in multiple cases
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+
+ // Legacy case uses an empty crop rect here, so we just preserve the
+ // source image verbatim
+ if (!wallpaper.cropHint.isEmpty()) {
+ // ...clamp the crop rect to the measured bounds...
+ wallpaper.cropHint.right = Math.min(wallpaper.cropHint.right, options.outWidth);
+ wallpaper.cropHint.bottom = Math.min(wallpaper.cropHint.bottom, options.outHeight);
+ // ...and don't bother cropping if what we're left with is identity
+ needCrop = (options.outHeight >= wallpaper.cropHint.height()
+ && options.outWidth >= wallpaper.cropHint.width());
+ }
+
+ if (!needCrop) {
+ // Simple case: the nominal crop is at least as big as the source image,
+ // so we take the whole thing and just copy the image file directly.
+ if (DEBUG) {
+ Slog.v(TAG, "Null crop of new wallpaper; copying");
+ }
+ success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+ if (!success) {
+ wallpaper.cropFile.delete();
+ // TODO: fall back to default wallpaper in this case
+ }
+ } else {
+ // Fancy case: the crop is a subrect of the source
+ FileOutputStream f = null;
+ BufferedOutputStream bos = null;
+ try {
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+ wallpaper.wallpaperFile.getAbsolutePath(), false);
+ Bitmap cropped = decoder.decodeRegion(wallpaper.cropHint, null);
+ decoder.recycle();
+
+ if (cropped == null) {
+ Slog.e(TAG, "Could not decode new wallpaper");
+ } else {
+ f = new FileOutputStream(wallpaper.cropFile);
+ bos = new BufferedOutputStream(f, 32*1024);
+ cropped.compress(Bitmap.CompressFormat.PNG, 90, bos);
+ bos.flush(); // don't rely on the implicit flush-at-close when noting success
+ success = true;
+ }
+ } catch (IOException e) {
+ if (DEBUG) {
+ Slog.e(TAG, "I/O error decoding crop: " + e.getMessage());
+ }
+ } finally {
+ IoUtils.closeQuietly(bos);
+ IoUtils.closeQuietly(f);
+ }
+ }
+
+ if (!success) {
+ Slog.e(TAG, "Unable to apply new wallpaper");
+ wallpaper.cropFile.delete();
+ }
+
+ if (wallpaper.cropFile.exists()) {
+ boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
+ if (DEBUG) {
+ Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
+ }
+ }
+ }
+
final Context mContext;
final IWindowManager mIWindowManager;
final IPackageManager mIPackageManager;
@@ -191,7 +289,8 @@
int userId;
- File wallpaperFile;
+ final File wallpaperFile;
+ final File cropFile;
/**
* Client is currently writing a new image wallpaper.
@@ -199,6 +298,11 @@
boolean imageWallpaperPending;
/**
+ * Callback once the set + crop is finished
+ */
+ IWallpaperManagerCallback setComplete;
+
+ /**
* Resource name if using a picture from the wallpaper gallery
*/
String name = "";
@@ -232,11 +336,26 @@
int width = -1;
int height = -1;
+ /**
+ * The crop hint supplied for displaying a subset of the source image
+ */
+ final Rect cropHint = new Rect(0, 0, 0, 0);
+
final Rect padding = new Rect(0, 0, 0, 0);
WallpaperData(int userId) {
this.userId = userId;
wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+ cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+ }
+
+ // Only called in single-threaded boot sequence mode
+ boolean ensureCropExists() {
+ // if the crop file is not present, copy over the source image to use verbatim
+ if (!cropFile.exists()) {
+ return FileUtils.copyFile(wallpaperFile, cropFile);
+ }
+ return true;
}
}
@@ -524,6 +643,9 @@
public void systemRunning() {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
+ if (!wallpaper.ensureCropExists()) {
+ clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null);
+ }
switchWallpaper(wallpaper, null);
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
wallpaper.wallpaperObserver.startWatching();
@@ -602,6 +724,8 @@
onStoppingUser(userId);
File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
wallpaperFile.delete();
+ File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+ cropFile.delete();
File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
wallpaperInfoFile.delete();
}
@@ -653,9 +777,9 @@
if (wallpaper == null) {
return;
}
- File f = new File(getWallpaperDir(userId), WALLPAPER);
- if (f.exists()) {
- f.delete();
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
+ wallpaper.cropFile.delete();
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -844,11 +968,10 @@
outParams.putInt("height", wallpaper.height);
}
wallpaper.callbacks.register(cb);
- File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
- if (!f.exists()) {
+ if (!wallpaper.cropFile.exists()) {
return null;
}
- return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+ return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
} catch (FileNotFoundException e) {
/* Shouldn't happen as we check to see if the file exists */
Slog.w(TAG, "Error getting wallpaper", e);
@@ -869,8 +992,8 @@
}
@Override
- public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Bundle extras,
- int which) {
+ public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
+ Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
if (which == 0) {
@@ -881,6 +1004,17 @@
return null;
}
+ // "null" means the no-op crop, preserving the full input image
+ if (cropHint == null) {
+ cropHint = new Rect(0, 0, 0, 0);
+ } else {
+ if (cropHint.isEmpty()
+ || cropHint.left < 0
+ || cropHint.top < 0) {
+ return null;
+ }
+ }
+
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
int userId = UserHandle.getCallingUserId();
@@ -890,6 +1024,8 @@
ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
if (pfd != null) {
wallpaper.imageWallpaperPending = true;
+ wallpaper.setComplete = completion;
+ wallpaper.cropHint.set(cropHint);
}
return pfd;
} finally {
@@ -1196,6 +1332,12 @@
out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
out.attribute(null, "width", Integer.toString(wallpaper.width));
out.attribute(null, "height", Integer.toString(wallpaper.height));
+
+ out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
+ out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
+ out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
+ out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+
if (wallpaper.padding.left != 0) {
out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
}
@@ -1208,6 +1350,7 @@
if (wallpaper.padding.bottom != 0) {
out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
}
+
out.attribute(null, "name", wallpaper.name);
if (wallpaper.wallpaperComponent != null
&& !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
@@ -1304,6 +1447,10 @@
wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
wallpaper.height = Integer.parseInt(parser
.getAttributeValue(null, "height"));
+ wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+ wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
+ wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
+ wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
@@ -1322,6 +1469,7 @@
if (DEBUG) {
Slog.v(TAG, "mWidth:" + wallpaper.width);
Slog.v(TAG, "mHeight:" + wallpaper.height);
+ Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Slog.v(TAG, "mName:" + wallpaper.name);
Slog.v(TAG, "mNextWallpaperComponent:"
+ wallpaper.nextWallpaperComponent);
@@ -1348,6 +1496,7 @@
if (!success) {
wallpaper.width = -1;
wallpaper.height = -1;
+ wallpaper.cropHint.set(0, 0, 0, 0);
wallpaper.padding.set(0, 0, 0, 0);
wallpaper.name = "";
} else {
@@ -1368,6 +1517,11 @@
if (wallpaper.height < baseSize) {
wallpaper.height = baseSize;
}
+ // and crop, if not previously specified
+ if (wallpaper.cropHint.width() <= 0
+ || wallpaper.cropHint.height() <= 0) {
+ wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
+ }
}
private int getMaximumSizeDimension() {
@@ -1431,6 +1585,7 @@
}
}
+ // Restore the named resource bitmap to both source + crop files
boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
String resName = wallpaper.name.substring(4);
@@ -1456,6 +1611,7 @@
int resId = -1;
InputStream res = null;
FileOutputStream fos = null;
+ FileOutputStream cos = null;
try {
Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
Resources r = c.getResources();
@@ -1469,13 +1625,16 @@
res = r.openRawResource(resId);
if (wallpaper.wallpaperFile.exists()) {
wallpaper.wallpaperFile.delete();
+ wallpaper.cropFile.delete();
}
fos = new FileOutputStream(wallpaper.wallpaperFile);
+ cos = new FileOutputStream(wallpaper.cropFile);
byte[] buffer = new byte[32768];
int amt;
while ((amt=res.read(buffer)) > 0) {
fos.write(buffer, 0, amt);
+ cos.write(buffer, 0, amt);
}
// mWallpaperObserver will notice the close and send the change broadcast
@@ -1491,8 +1650,12 @@
IoUtils.closeQuietly(res);
if (fos != null) {
FileUtils.sync(fos);
- IoUtils.closeQuietly(fos);
}
+ if (cos != null) {
+ FileUtils.sync(cos);
+ }
+ IoUtils.closeQuietly(fos);
+ IoUtils.closeQuietly(cos);
}
}
}
@@ -1520,6 +1683,7 @@
pw.print(wallpaper.width);
pw.print(" mHeight=");
pw.println(wallpaper.height);
+ pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
pw.print(" mPadding="); pw.println(wallpaper.padding);
pw.print(" mName="); pw.println(wallpaper.name);
pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index e0880ad..e6fa837 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -74,6 +74,12 @@
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
+ /** Screen content area excluding IM windows, etc. */
+ private final Rect mContentBounds = new Rect();
+
+ /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
+ private final Rect mAdjustedBounds = new Rect();
+
/** Whether mBounds is fullscreen */
private boolean mFullscreen = true;
@@ -164,6 +170,85 @@
return mTmpRect.equals(bounds);
}
+ void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+ if (mFullscreen) {
+ return;
+ }
+ // Update bounds of containing tasks.
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTasks.get(taskNdx);
+ if (task.isTwoFingerScrollMode()) {
+ // If we're scrolling we don't care about your bounds or configs,
+ // they should be null as if we were in fullscreen.
+ task.resizeLocked(null, null, false /* forced */);
+ task.getBounds(mTmpRect2);
+ task.scrollLocked(mTmpRect2);
+ } else if (task.isResizeable()) {
+ task.getBounds(mTmpRect2);
+ mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+ task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
+ }
+ }
+ }
+
+ void adjustForIME(final WindowState imeWin) {
+ final int dockedSide = getDockSide();
+ final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+ final Rect adjustedBounds = mAdjustedBounds;
+ if (imeWin == null || !dockedTopOrBottom) {
+ // If mContentBounds is already empty, it means we're not applying
+ // any adjustments, so nothing to do; otherwise clear any adjustments.
+ if (!mContentBounds.isEmpty()) {
+ mContentBounds.setEmpty();
+ adjustedBounds.set(mBounds);
+ alignTasksToAdjustedBounds(adjustedBounds);
+ }
+ return;
+ }
+
+ final Rect displayContentRect = mTmpRect;
+ final Rect contentBounds = mTmpRect2;
+
+ // Calculate the content bounds excluding the area occupied by IME
+ mDisplayContent.getContentRect(displayContentRect);
+ contentBounds.set(displayContentRect);
+ int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+ imeTop += imeWin.getGivenContentInsetsLw().top;
+ if (contentBounds.bottom > imeTop) {
+ contentBounds.bottom = imeTop;
+ }
+
+ // If content bounds not changing, nothing to do.
+ if (mContentBounds.equals(contentBounds)) {
+ return;
+ }
+
+ // Content bounds changed, need to apply adjustments depending on dock sides.
+ mContentBounds.set(contentBounds);
+ adjustedBounds.set(mBounds);
+ final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+ if (dockedSide == DOCKED_TOP) {
+ // If this stack is docked on top, we make it smaller so the bottom stack is not
+ // occluded by IME. We shift its bottom up by the height of the IME (capped by
+ // the display content rect). Note that we don't change the task bounds.
+ adjustedBounds.bottom = Math.max(
+ adjustedBounds.bottom - yOffset, displayContentRect.top);
+ } else {
+ // If this stack is docked on bottom, we shift it up so that it's not occluded by
+ // IME. We try to move it up by the height of the IME window (although the best
+ // we could do is to make the top stack fully collapsed).
+ final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
+ adjustedBounds.top = Math.max(
+ adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+ adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+
+ // We also move the member tasks together, taking care not to resize them.
+ // Resizing might cause relaunch, and IME window may not come back after that.
+ alignTasksToAdjustedBounds(adjustedBounds);
+ }
+ }
+
private boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
@@ -193,6 +278,16 @@
mBounds.set(bounds);
mRotation = rotation;
+
+ // Clear the adjusted content bounds as they're no longer valid.
+ // If IME is still visible, these will be re-applied.
+ // Note that we don't clear mContentBounds here, so that we know the last IME
+ // adjust we applied.
+ // If user starts dragging the dock divider while IME is visible, the new bounds
+ // we received are based on the actual screen location of the divider. It already
+ // accounted for the IME window, so we don't want to adjust again.
+ mAdjustedBounds.set(mBounds);
+
return true;
}
@@ -217,9 +312,14 @@
public void getBounds(Rect out) {
if (useCurrentBounds()) {
- // No need to adjust the output bounds if fullscreen or the docked stack is visible
+ // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
+ // no need to adjust the output bounds if fullscreen or the docked stack is visible
// since it is already what we want to represent to the rest of the system.
- out.set(mBounds);
+ if (!mContentBounds.isEmpty()) {
+ out.set(mAdjustedBounds);
+ } else {
+ out.set(mBounds);
+ }
return;
}
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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2b88af4..e0e44dc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -161,6 +161,7 @@
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -8075,8 +8076,29 @@
}
case UPDATE_DOCKED_STACK_DIVIDER: {
synchronized (mWindowMap) {
- getDefaultDisplayContentLocked().getDockedDividerController()
- .reevaluateVisibility(false);
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+
+ displayContent.getDockedDividerController().reevaluateVisibility(false);
+
+ final WindowState imeWin = mInputMethodWindow;
+ final TaskStack focusedStack =
+ mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+ if (imeWin != null && focusedStack != null && imeWin.isVisibleNow()
+ && focusedStack.getDockSide() == DOCKED_BOTTOM){
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack.isVisibleLocked()) {
+ stack.adjustForIME(imeWin);
+ }
+ }
+ } else {
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ stack.adjustForIME(null);
+ }
+ }
}
}
break;
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");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 236ae68e..7831c4d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -195,7 +195,7 @@
private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
- protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
+ private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
@@ -509,6 +509,7 @@
private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
private static final String TAG_PARENT_ADMIN = "parent-admin";
private static final String TAG_ORGANIZATION_COLOR = "organization-color";
+ private static final String TAG_ORGANIZATION_NAME = "organization-name";
final DeviceAdminInfo info;
@@ -607,6 +608,9 @@
static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
int organizationColor = DEF_ORGANIZATION_COLOR;
+ // Default title of confirm credentials screen
+ String organizationName = null;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
isParent = parent;
@@ -830,6 +834,11 @@
out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
out.endTag(null, TAG_ORGANIZATION_COLOR);
}
+ if (organizationName != null) {
+ out.startTag(null, TAG_ORGANIZATION_NAME);
+ out.text(organizationName);
+ out.endTag(null, TAG_ORGANIZATION_NAME);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -971,6 +980,13 @@
} else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
organizationColor = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ORGANIZATION_NAME.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ organizationName = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading organization name");
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1179,6 +1195,12 @@
pw.print(prefix); pw.print("keepUninstalledPackages=");
pw.println(keepUninstalledPackages);
}
+ pw.print(prefix); pw.print("organizationColor=");
+ pw.println(organizationColor);
+ if (organizationName != null) {
+ pw.print(prefix); pw.print("organizationName=");
+ pw.println(organizationName);
+ }
pw.print(prefix); pw.println("userRestrictions:");
UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions);
pw.print(prefix); pw.print("isParent=");
@@ -1703,8 +1725,8 @@
* Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
* reminders. Clears alarm if no expirations are configured.
*/
- private void setExpirationAlarmCheckLocked(Context context, int userHandle) {
- final long expiration = getPasswordExpirationLocked(null, userHandle, /* parent */ false);
+ private void setExpirationAlarmCheckLocked(Context context, int userHandle, boolean parent) {
+ final long expiration = getPasswordExpirationLocked(null, userHandle, parent);
final long now = System.currentTimeMillis();
final long timeToExpire = expiration - now;
final long alarmTime;
@@ -1726,11 +1748,12 @@
long token = mInjector.binderClearCallingIdentity();
try {
+ int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
- UserHandle.of(userHandle));
+ UserHandle.of(affectedUserHandle));
am.cancel(pi);
if (alarmTime != 0) {
am.set(AlarmManager.RTC, alarmTime, pi);
@@ -2489,7 +2512,6 @@
synchronized (this) {
final long now = System.currentTimeMillis();
- // Return the strictest policy across all participating admins.
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
userHandle, /* parent */ false);
final int N = admins.size();
@@ -2503,7 +2525,7 @@
DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
}
}
- setExpirationAlarmCheckLocked(mContext, userHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
}
}
@@ -2976,8 +2998,7 @@
saveSettingsLocked(userHandle);
// in case this is the first one, set the alarm on the appropriate user.
- int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
- setExpirationAlarmCheckLocked(mContext, affectedUserHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, parent);
}
}
@@ -4324,7 +4345,7 @@
policy.mFailedPasswordAttempts = 0;
saveSettingsLocked(userHandle);
updatePasswordExpirationsLocked(userHandle);
- setExpirationAlarmCheckLocked(mContext, userHandle);
+ setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
// Send a broadcast to each profile using this password as its primary unlock.
sendAdminCommandForLockscreenPoliciesLocked(
@@ -6772,6 +6793,8 @@
@Override
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
Preconditions.checkNotNull(who, "ComponentName is null");
+ UserRestrictionsUtils.checkRestriction(key);
+
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
ActiveAdmin activeAdmin =
@@ -8097,11 +8120,12 @@
@Override
public void setOrganizationColor(@NonNull ComponentName who, int color) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8112,11 +8136,11 @@
@Override
public int getOrganizationColor(@NonNull ComponentName who) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8126,10 +8150,11 @@
@Override
public int getOrganizationColorForUser(int userHandle) {
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- enforceCrossUsersPermission(userHandle);
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization color");
synchronized (this) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
return (profileOwner != null)
@@ -8139,6 +8164,53 @@
}
@Override
+ public void setOrganizationName(@NonNull ComponentName who, String text) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization name");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!TextUtils.equals(admin.organizationName, text)) {
+ admin.organizationName = TextUtils.nullIfEmpty(text);
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getOrganizationName(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+ synchronized(this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return admin.organizationName;
+ }
+ }
+
+ @Override
+ public String getOrganizationNameForUser(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization name");
+ synchronized (this) {
+ ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+ return (profileOwner != null)
+ ? profileOwner.organizationName
+ : null;
+ }
+ }
+
+ @Override
public void setAffiliationIds(ComponentName admin, List<String> ids) {
final Set<String> affiliationIds = new ArraySet<String>(ids);
final int callingUserId = mInjector.userHandleGetCallingUserId();
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b4bca3e..6c2fcd5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -26,7 +26,10 @@
import android.os.UserManager;
import android.test.AndroidTestCase;
+import com.android.internal.util.ArrayUtils;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/** Test {@link UserManager} functionality. */
@@ -196,6 +199,17 @@
assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
}
+ public void testGetSerialNumbersOfUsers() {
+ UserInfo user1 = createUser("User 1", 0);
+ UserInfo user2 = createUser("User 2", 0);
+ long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
+ String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
+ assertTrue(errMsg + user1.serialNumber,
+ ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
+ assertTrue(errMsg + user2.serialNumber,
+ ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
+ }
+
public void testMaxUsers() {
int N = UserManager.getMaxSupportedUsers();
int count = mUserManager.getUsers().size();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 81031da..77740387 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -123,6 +123,7 @@
static final int MSG_PAROLE_END_TIMEOUT = 7;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
+ static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
private final Object mLock = new Object();
Handler mHandler;
@@ -144,8 +145,10 @@
private boolean mScreenOn;
private long mLastAppIdleParoledTime;
+ private volatile boolean mPendingOneTimeCheckIdleStates;
+
long mScreenOnTime;
- long mScreenOnSystemTimeSnapshot;
+ long mLastScreenOnEventRealtime;
@GuardedBy("mLock")
private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
@@ -188,6 +191,8 @@
synchronized (mLock) {
cleanUpRemovedUsersLocked();
+ mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
+ mScreenOnTime = readScreenOnTimeLocked();
}
mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -214,14 +219,14 @@
Context.DISPLAY_SERVICE);
mPowerManager = getContext().getSystemService(PowerManager.class);
- mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
- synchronized (mLock) {
- mScreenOnTime = readScreenOnTimeLocked();
- }
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
synchronized (mLock) {
updateDisplayLocked();
}
+
+ if (mPendingOneTimeCheckIdleStates) {
+ postOneTimeCheckIdleStates();
+ }
} else if (phase == PHASE_BOOT_COMPLETED) {
setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
}
@@ -281,6 +286,11 @@
}
@Override
+ public void onStatsReloaded() {
+ postOneTimeCheckIdleStates();
+ }
+
+ @Override
public long getAppIdleRollingWindowDurationMillis() {
return mAppIdleWallclockThresholdMillis * 2;
}
@@ -359,6 +369,20 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
+ /**
+ * We send a different message to check idle states once, otherwise we would end up
+ * scheduling a series of repeating checkIdleStates each time we fired off one.
+ */
+ void postOneTimeCheckIdleStates() {
+ if (mDeviceIdleController == null) {
+ // Not booted yet; wait for it!
+ mPendingOneTimeCheckIdleStates = true;
+ } else {
+ mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ mPendingOneTimeCheckIdleStates = false;
+ }
+ }
+
/** Check all running users' or specified user's apps to see if they enter an idle state. */
void checkIdleStates(int checkUserId) {
if (!mAppIdleEnabled) {
@@ -385,7 +409,7 @@
userId);
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
timeNow);
final int packageCount = packages.size();
@@ -401,8 +425,6 @@
}
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
- mCheckIdleIntervalMillis);
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -443,21 +465,21 @@
if (screenOn == mScreenOn) return;
mScreenOn = screenOn;
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
if (mScreenOn) {
- mScreenOnSystemTimeSnapshot = now;
+ mLastScreenOnEventRealtime = now;
} else {
- mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
+ mScreenOnTime += now - mLastScreenOnEventRealtime;
writeScreenOnTimeLocked(mScreenOnTime);
}
}
- private long getScreenOnTimeLocked(long now) {
+ long getScreenOnTimeLocked() {
+ long screenOnTime = mScreenOnTime;
if (mScreenOn) {
- return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
- } else {
- return mScreenOnTime;
+ screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
}
+ return screenOnTime;
}
private File getScreenOnTimeFile() {
@@ -527,7 +549,7 @@
if (service == null) {
service = new UserUsageStatsService(getContext(), userId,
new File(mUsageStatsDir, Integer.toString(userId)), this);
- service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
+ service.init(currentTimeMillis, getScreenOnTimeLocked());
mUserState.put(userId, service);
}
return service;
@@ -540,25 +562,18 @@
final long actualSystemTime = System.currentTimeMillis();
final long actualRealtime = SystemClock.elapsedRealtime();
final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
- boolean resetBeginIdleTime = false;
- if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+ final long diffSystemTime = actualSystemTime - expectedSystemTime;
+ if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
// The time has changed.
-
- // Check if it's severe enough a change to reset screenOnTime
- if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
- mScreenOnSystemTimeSnapshot = actualSystemTime;
- mScreenOnTime = 0;
- resetBeginIdleTime = true;
- }
+ Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
final UserUsageStatsService service = mUserState.valueAt(i);
- service.onTimeChanged(expectedSystemTime, actualSystemTime, mScreenOnTime,
- resetBeginIdleTime);
+ service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
+ false);
}
mRealTimeSnapshot = actualRealtime;
mSystemTimeSnapshot = actualSystemTime;
- postCheckIdleStates(UserHandle.USER_ALL);
}
return actualSystemTime;
}
@@ -587,7 +602,7 @@
void reportEvent(UsageEvents.Event event, int userId) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
convertToSystemTimeLocked(event);
final UserUsageStatsService service =
@@ -603,7 +618,6 @@
|| event.mEventType == Event.SYSTEM_INTERACTION
|| event.mEventType == Event.USER_INTERACTION)) {
if (previouslyIdle) {
- //Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
@@ -643,7 +657,7 @@
void forceIdleState(String packageName, int userId, boolean idle) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
final UserUsageStatsService service =
@@ -657,7 +671,6 @@
timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
- // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
if (!idle) {
@@ -796,7 +809,7 @@
timeNow = checkAndGetTimeLocked();
}
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
userService, timeNow, screenOnTime);
@@ -865,7 +878,7 @@
synchronized (mLock) {
timeNow = checkAndGetTimeLocked();
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
List<ApplicationInfo> apps;
@@ -987,7 +1000,7 @@
*/
void dump(String[] args, PrintWriter pw) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
+ final long screenOnTime = getScreenOnTimeLocked();
IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
ArraySet<String> argSet = new ArraySet<>();
argSet.addAll(Arrays.asList(args));
@@ -1008,7 +1021,11 @@
}
idpw.decreaseIndent();
}
- pw.println("Screen On Timebase:" + mScreenOnTime);
+ pw.print("Screen On Timebase: ");
+ pw.print(screenOnTime);
+ pw.print(" (");
+ TimeUtils.formatDuration(screenOnTime, pw);
+ pw.println(")");
pw.println();
pw.println("Settings:");
@@ -1042,8 +1059,8 @@
pw.println();
pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
pw.println();
- pw.print("mScreenOnSystemTimeSnapshot=");
- TimeUtils.formatDuration(mScreenOnSystemTimeSnapshot, pw);
+ pw.print("mLastScreenOnEventRealtime=");
+ TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
pw.println();
}
}
@@ -1078,6 +1095,14 @@
case MSG_CHECK_IDLE_STATES:
checkIdleStates(msg.arg1);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+ mCheckIdleIntervalMillis);
+ break;
+
+ case MSG_ONE_TIME_CHECK_IDLE_STATES:
+ mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ checkIdleStates(UserHandle.USER_ALL);
break;
case MSG_CHECK_PAROLE_TIMEOUT:
@@ -1138,7 +1163,7 @@
@Override
public void onChange(boolean selfChange) {
updateSettings();
- postCheckIdleStates(UserHandle.USER_ALL);
+ postOneTimeCheckIdleStates();
}
void updateSettings() {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index aa2cf77..f2045d3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -73,6 +73,7 @@
interface StatsUpdatedListener {
void onStatsUpdated();
+ void onStatsReloaded();
long getAppIdleRollingWindowDurationMillis();
}
@@ -523,6 +524,9 @@
mStatsChanged = false;
updateRolloverDeadline();
+
+ // Tell the listener that the stats reloaded, which may have changed idle states.
+ mListener.onStatsReloaded();
}
private void updateRolloverDeadline() {
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index c65e8ba..84883d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -48,7 +48,9 @@
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+ if (txTimeMs != null) {
+ System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+ }
mRxTimeMs = rxTimeMs;
mEnergyUsed = energyUsed;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
index 5dffa28..069fcbf 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
@@ -16,8 +16,9 @@
package com.android.internal.telephony;
-import android.os.Bundle;
+import com.android.internal.telephony.ITelephonyDebugSubscriber;
+import android.os.Bundle;
/**
* Interface used to interact with the Telephony debug service.
@@ -36,4 +37,7 @@
* @param data optional
*/
void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
+
+ void subscribe(in ITelephonyDebugSubscriber subscriber);
+ void unsubscribe(in ITelephonyDebugSubscriber subscriber);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
new file mode 100644
index 0000000..64eb0f1
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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 com.android.internal.telephony;
+
+import com.android.internal.telephony.TelephonyEvent;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to subscribe for events from Telephony debug service.
+ *
+ * {@hide}
+ */
+oneway interface ITelephonyDebugSubscriber {
+
+ /**
+ * Called when Telephony debug service has events.
+ */
+ void onEvents(in TelephonyEvent[] events);
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
new file mode 100644
index 0000000..1e74b31
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 com.android.internal.telephony;
+
+parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
new file mode 100644
index 0000000..26d466d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
@@ -0,0 +1,84 @@
+/*
+ * 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 com.android.internal.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable used in ITelephonyDebugSubscriber.aidl
+ */
+public class TelephonyEvent implements Parcelable {
+
+ final public long timestamp;
+ final public int phoneId;
+ final public int tag;
+ final public int param1;
+ final public int param2;
+ final public Bundle data;
+
+ public TelephonyEvent(long timestamp, int phoneId, int tag,
+ int param1, int param2, Bundle data) {
+ this.timestamp = timestamp;
+ this.phoneId = phoneId;
+ this.tag = tag;
+ this.param1 = param1;
+ this.param2 = param2;
+ this.data = data;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<TelephonyEvent> CREATOR
+ = new Parcelable.Creator<TelephonyEvent> (){
+ public TelephonyEvent createFromParcel(Parcel source) {
+ final long timestamp = source.readLong();
+ final int phoneId = source.readInt();
+ final int tag = source.readInt();
+ final int param1 = source.readInt();
+ final int param2 = source.readInt();
+ final Bundle data = source.readBundle();
+ return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
+ }
+
+ public TelephonyEvent[] newArray(int size) {
+ return new TelephonyEvent[size];
+ }
+ };
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(timestamp);
+ dest.writeInt(phoneId);
+ dest.writeInt(tag);
+ dest.writeInt(param1);
+ dest.writeInt(param2);
+ dest.writeBundle(data);
+ }
+
+ public String toString() {
+ return String.format("%d,%d,%d,%d,%d,%s",
+ timestamp, phoneId, tag, param1, param2, data);
+ }
+}
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
new file mode 100644
index 0000000..0e2467f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#f00" android:state_pressed="true" />
+ <item android:color="#00f" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
new file mode 100644
index 0000000..7e6c8ce
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.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.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#00f" android:state_pressed="true" />
+ <item android:color="#f00" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
new file mode 100644
index 0000000..9f08fe8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
@@ -0,0 +1,31 @@
+<?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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24" >
+
+ <path
+ android:fillColor="@color/vector_icon_fill_state_list_simple"
+ android:strokeColor="@color/vector_icon_stroke_state_list_simple"
+ android:strokeWidth="3"
+ android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index a7da286..7172147 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -38,7 +38,8 @@
R.drawable.vector_icon_gradient_1,
R.drawable.vector_icon_gradient_2,
R.drawable.vector_icon_gradient_3,
- R.drawable.vector_icon_state_list,
+ R.drawable.vector_icon_state_list_simple,
+ R.drawable.vector_icon_state_list_theme,
R.drawable.vector_drawable01,
R.drawable.vector_drawable02,
R.drawable.vector_drawable03,
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index ff3d29f..ec9e462 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -43,7 +43,8 @@
void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings);
void subscribe(int sessionId, in SubscribeData subscribeData,
in SubscribeSettings subscribeSettings);
- void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength);
+ void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength,
+ int messageId);
void stopSession(int sessionId);
void destroySession(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
index 773f83b..50c34d9 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
@@ -32,7 +32,7 @@
void onMatch(int peerId, in byte[] serviceSpecificInfo,
int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength);
- void onMessageSendSuccess();
- void onMessageSendFail(int reason);
+ void onMessageSendSuccess(int messageId);
+ void onMessageSendFail(int messageId, int reason);
void onMessageReceived(int peerId, in byte[] message, int messageLength);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 877f993..cb82268 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -319,13 +319,14 @@
/**
* {@hide}
*/
- public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength) {
+ public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength,
+ int messageId) {
try {
if (VDBG) {
Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
- + ", messageLength=" + messageLength);
+ + ", messageLength=" + messageLength + ", messageId=" + messageId);
}
- mService.sendMessage(sessionId, peerId, message, messageLength);
+ mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
} catch (RemoteException e) {
Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c6b384e..d0a9410 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -103,8 +103,11 @@
* @param message The message to be transmitted.
* @param messageLength The number of bytes from the {@code message} to be
* transmitted.
+ * @param messageId An arbitrary integer used by the caller to identify the
+ * message. The same integer ID will be returned in the callbacks
+ * indicated message send success or failure.
*/
- public void sendMessage(int peerId, byte[] message, int messageLength) {
- mManager.sendMessage(mSessionId, peerId, message, messageLength);
+ public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) {
+ mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId);
}
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index c9d08c7..d5e59f0 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -210,10 +210,10 @@
msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2);
break;
case LISTEN_MESSAGE_SEND_SUCCESS:
- WifiNanSessionListener.this.onMessageSendSuccess();
+ WifiNanSessionListener.this.onMessageSendSuccess(msg.arg1);
break;
case LISTEN_MESSAGE_SEND_FAIL:
- WifiNanSessionListener.this.onMessageSendFail(msg.arg1);
+ WifiNanSessionListener.this.onMessageSendFail(msg.arg1, msg.arg2);
break;
case LISTEN_MESSAGE_RECEIVED:
WifiNanSessionListener.this.onMessageReceived(msg.arg2,
@@ -306,7 +306,7 @@
* {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
* never both.
*/
- public void onMessageSendSuccess() {
+ public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
}
@@ -325,7 +325,7 @@
* @param reason The failure reason using {@code NanSessionListener.FAIL_*}
* codes.
*/
- public void onMessageSendFail(int reason) {
+ public void onMessageSendFail(int messageId, int reason) {
if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested");
}
@@ -401,19 +401,21 @@
}
@Override
- public void onMessageSendSuccess() {
+ public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess");
Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS);
+ msg.arg1 = messageId;
mHandler.sendMessage(msg);
}
@Override
- public void onMessageSendFail(int reason) {
+ public void onMessageSendFail(int messageId, int reason) {
if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL);
- msg.arg1 = reason;
+ msg.arg1 = messageId;
+ msg.arg2 = reason;
mHandler.sendMessage(msg);
}