diff options
257 files changed, 7527 insertions, 1617 deletions
diff --git a/Android.mk b/Android.mk index 5983b308bddb..ad164e207b9b 100644 --- a/Android.mk +++ b/Android.mk @@ -187,6 +187,8 @@ LOCAL_SRC_FILES += \ 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 @@ LOCAL_SRC_FILES += \ 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 ebeaefc353fc..a501ce7d1346 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4642,6 +4642,7 @@ package android.app { method public android.content.Context getContext(); method public android.content.Context getTargetContext(); method public android.app.UiAutomation getUiAutomation(); + method public android.app.UiAutomation getUiAutomation(int); method public boolean invokeContextMenuAction(android.app.Activity, int, int); method public boolean invokeMenuActionSync(android.app.Activity, int, int); method public boolean isProfiling(); @@ -5538,6 +5539,7 @@ package android.app { public final class UiAutomation { method public void clearWindowAnimationFrameStats(); method public boolean clearWindowContentFrameStats(int); + method public void destroy(); method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException; method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); @@ -5554,6 +5556,7 @@ package android.app { 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 +5824,7 @@ package android.app.admin { 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 +5894,7 @@ package android.app.admin { 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); @@ -19871,6 +19876,7 @@ package android.media { 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 +19948,8 @@ package android.media { 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 +22504,7 @@ package android.media.session { 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 +22583,7 @@ package android.media.session { 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 +22900,7 @@ package android.media.tv { method public void onInputAdded(java.lang.String); method public void onInputRemoved(java.lang.String); method public void onInputStateChanged(java.lang.String, int); - method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo); + method public void onTvInputInfoChanged(android.media.tv.TvInputInfo); } public abstract class TvInputService extends android.app.Service { @@ -22898,7 +22908,7 @@ package android.media.tv { method public final android.os.IBinder onBind(android.content.Intent); method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String); method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String); - method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo); + method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo); field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService"; field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input"; } @@ -28536,6 +28546,10 @@ package android.os { 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 +29141,7 @@ package android.os { 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 +29607,8 @@ package android.preference { 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 +32059,7 @@ package android.provider { 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"; @@ -37186,7 +37204,7 @@ package android.test { method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception; } - public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase { + public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase { ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>); ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>); method public T getActivity(); @@ -37194,14 +37212,14 @@ package android.test { method public void setActivityIntent(android.content.Intent); } - public abstract class ActivityTestCase extends android.test.InstrumentationTestCase { + public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase { ctor public ActivityTestCase(); method protected android.app.Activity getActivity(); method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException; method protected void setActivity(android.app.Activity); } - public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase { + public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase { ctor public ActivityUnitTestCase(java.lang.Class<T>); method public T getActivity(); method public int getFinishedActivityRequest(); @@ -37214,7 +37232,7 @@ package android.test { method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object); } - public class AndroidTestCase extends junit.framework.TestCase { + public deprecated class AndroidTestCase extends junit.framework.TestCase { ctor public AndroidTestCase(); method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String); method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String); @@ -37226,7 +37244,7 @@ package android.test { field protected android.content.Context mContext; } - public class AndroidTestRunner extends junit.runner.BaseTestRunner { + public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner { ctor public AndroidTestRunner(); method public void addTestListener(junit.framework.TestListener); method public void clearTestListeners(); @@ -37247,7 +37265,7 @@ package android.test { method public void testStarted(java.lang.String); } - public abstract class ApplicationTestCase extends android.test.AndroidTestCase { + public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase { ctor public ApplicationTestCase(java.lang.Class<T>); method protected final void createApplication(); method public T getApplication(); @@ -37265,10 +37283,10 @@ package android.test { ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String); } - public abstract class FlakyTest implements java.lang.annotation.Annotation { + public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation { } - public class InstrumentationTestCase extends junit.framework.TestCase { + public deprecated class InstrumentationTestCase extends junit.framework.TestCase { ctor public InstrumentationTestCase(); method public android.app.Instrumentation getInstrumentation(); method public deprecated void injectInsrumentation(android.app.Instrumentation); @@ -37281,7 +37299,7 @@ package android.test { method public void sendRepeatedKeys(int...); } - public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider { + public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider { ctor public InstrumentationTestRunner(); method public junit.framework.TestSuite getAllTests(); method protected android.test.AndroidTestRunner getAndroidTestRunner(); @@ -37300,14 +37318,14 @@ package android.test { field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1 } - public class InstrumentationTestSuite extends junit.framework.TestSuite { + public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite { ctor public InstrumentationTestSuite(android.app.Instrumentation); ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation); ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation); method public void addTestSuite(java.lang.Class); } - public class IsolatedContext extends android.content.ContextWrapper { + public deprecated class IsolatedContext extends android.content.ContextWrapper { ctor public IsolatedContext(android.content.ContentResolver, android.content.Context); method public java.util.List<android.content.Intent> getAndClearBroadcastIntents(); } @@ -37317,7 +37335,7 @@ package android.test { method public T getLoaderResultSynchronously(android.content.Loader<T>); } - public final class MoreAsserts { + public final deprecated class MoreAsserts { method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object); method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>); method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String); @@ -37356,7 +37374,7 @@ package android.test { method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean); } - public abstract interface PerformanceTestCase { + public abstract deprecated interface PerformanceTestCase { method public abstract boolean isPerformanceOnly(); method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates); } @@ -37385,7 +37403,7 @@ package android.test { method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException; } - public class RenamingDelegatingContext extends android.content.ContextWrapper { + public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper { ctor public RenamingDelegatingContext(android.content.Context, java.lang.String); ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String); method public java.lang.String getDatabasePrefix(); @@ -37394,7 +37412,7 @@ package android.test { method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException; } - public abstract class ServiceTestCase extends android.test.AndroidTestCase { + public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase { ctor public ServiceTestCase(java.lang.Class<T>); method protected android.os.IBinder bindService(android.content.Intent); method public android.app.Application getApplication(); @@ -37407,23 +37425,23 @@ package android.test { method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception; } - public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase { + public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase { ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>); method public T getActivity(); method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception; } - public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase { + public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase { ctor public SyncBaseInstrumentation(); method protected void cancelSyncsandDisableAutoSync(); method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception; } - public abstract interface TestSuiteProvider { + public abstract deprecated interface TestSuiteProvider { method public abstract junit.framework.TestSuite getTestSuite(); } - public class TouchUtils { + public deprecated class TouchUtils { ctor public TouchUtils(); method public static void clickView(android.test.InstrumentationTestCase, android.view.View); method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int); @@ -37458,10 +37476,10 @@ package android.test { method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View); } - public abstract class UiThreadTest implements java.lang.annotation.Annotation { + public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation { } - public class ViewAsserts { + public deprecated class ViewAsserts { method public static void assertBaselineAligned(android.view.View, android.view.View); method public static void assertBottomAligned(android.view.View, android.view.View); method public static void assertBottomAligned(android.view.View, android.view.View, int); @@ -37486,11 +37504,11 @@ package android.test { package android.test.mock { - public class MockApplication extends android.app.Application { + public deprecated class MockApplication extends android.app.Application { ctor public MockApplication(); } - public class MockContentProvider extends android.content.ContentProvider { + public deprecated class MockContentProvider extends android.content.ContentProvider { ctor protected MockContentProvider(); ctor public MockContentProvider(android.content.Context); ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]); @@ -37502,13 +37520,13 @@ package android.test.mock { method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); } - public class MockContentResolver extends android.content.ContentResolver { + public deprecated class MockContentResolver extends android.content.ContentResolver { ctor public MockContentResolver(); ctor public MockContentResolver(android.content.Context); method public void addProvider(java.lang.String, android.content.ContentProvider); } - public class MockContext extends android.content.Context { + public deprecated class MockContext extends android.content.Context { ctor public MockContext(); method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int); method public int checkCallingOrSelfPermission(java.lang.String); @@ -37608,7 +37626,7 @@ package android.test.mock { method public void unregisterReceiver(android.content.BroadcastReceiver); } - public class MockCursor implements android.database.Cursor { + public deprecated class MockCursor implements android.database.Cursor { ctor public MockCursor(); method public void close(); method public void copyStringToBuffer(int, android.database.CharArrayBuffer); @@ -37653,13 +37671,13 @@ package android.test.mock { method public void unregisterDataSetObserver(android.database.DataSetObserver); } - public class MockDialogInterface implements android.content.DialogInterface { + public deprecated class MockDialogInterface implements android.content.DialogInterface { ctor public MockDialogInterface(); method public void cancel(); method public void dismiss(); } - public class MockPackageManager extends android.content.pm.PackageManager { + public deprecated class MockPackageManager extends android.content.pm.PackageManager { ctor public MockPackageManager(); method public void addPackageToPreferred(java.lang.String); method public boolean addPermission(android.content.pm.PermissionInfo); @@ -37746,7 +37764,7 @@ package android.test.mock { method public void verifyPendingInstall(int, int); } - public class MockResources extends android.content.res.Resources { + public deprecated class MockResources extends android.content.res.Resources { ctor public MockResources(); } @@ -37787,19 +37805,19 @@ package android.test.suitebuilder { package android.test.suitebuilder.annotation { - public abstract class LargeTest implements java.lang.annotation.Annotation { + public abstract deprecated class LargeTest implements java.lang.annotation.Annotation { } - public abstract class MediumTest implements java.lang.annotation.Annotation { + public abstract deprecated class MediumTest implements java.lang.annotation.Annotation { } - public abstract class SmallTest implements java.lang.annotation.Annotation { + public abstract deprecated class SmallTest implements java.lang.annotation.Annotation { } - public abstract class Smoke implements java.lang.annotation.Annotation { + public abstract deprecated class Smoke implements java.lang.annotation.Annotation { } - public abstract class Suppress implements java.lang.annotation.Annotation { + public abstract deprecated class Suppress implements java.lang.annotation.Annotation { } } @@ -51298,6 +51316,9 @@ package java.lang.annotation { 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/removed.txt b/api/removed.txt index 6b7961e9f1f6..2c6729d2c159 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -201,7 +201,7 @@ package android.provider { package android.test.mock { - public class MockPackageManager extends android.content.pm.PackageManager { + public deprecated class MockPackageManager extends android.content.pm.PackageManager { method public deprecated java.lang.String getDefaultBrowserPackageName(int); method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int); } diff --git a/api/system-current.txt b/api/system-current.txt index 07e30a85d04b..dc8e5da04ffd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4774,6 +4774,7 @@ package android.app { method public android.content.Context getContext(); method public android.content.Context getTargetContext(); method public android.app.UiAutomation getUiAutomation(); + method public android.app.UiAutomation getUiAutomation(int); method public boolean invokeContextMenuAction(android.app.Activity, int, int); method public boolean invokeMenuActionSync(android.app.Activity, int, int); method public boolean isProfiling(); @@ -5670,6 +5671,7 @@ package android.app { public final class UiAutomation { method public void clearWindowAnimationFrameStats(); method public boolean clearWindowContentFrameStats(int); + method public void destroy(); method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException; method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); @@ -5686,6 +5688,7 @@ package android.app { 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 +5964,7 @@ package android.app.admin { 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 +6040,7 @@ package android.app.admin { 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); @@ -9956,6 +9961,7 @@ package android.content.pm { 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 +15129,66 @@ package android.hardware.input { 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 +15305,89 @@ package android.hardware.location { 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 +21142,7 @@ package android.media { 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 +21216,8 @@ package android.media { 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 +23845,7 @@ package android.media.session { 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 +23924,7 @@ package android.media.session { 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 +24415,7 @@ package android.media.tv { 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 +24427,7 @@ package android.media.tv { 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"; } @@ -30420,6 +30574,10 @@ package android.os { 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 +31177,7 @@ package android.os { 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 +31221,7 @@ package android.os { 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 +31236,7 @@ package android.os { 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 +31654,9 @@ package android.preference { 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 +34239,7 @@ package android.provider { 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"; @@ -39446,7 +39611,7 @@ package android.test { method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception; } - public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase { + public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase { ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>); ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>); method public T getActivity(); @@ -39454,14 +39619,14 @@ package android.test { method public void setActivityIntent(android.content.Intent); } - public abstract class ActivityTestCase extends android.test.InstrumentationTestCase { + public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase { ctor public ActivityTestCase(); method protected android.app.Activity getActivity(); method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException; method protected void setActivity(android.app.Activity); } - public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase { + public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase { ctor public ActivityUnitTestCase(java.lang.Class<T>); method public T getActivity(); method public int getFinishedActivityRequest(); @@ -39474,7 +39639,7 @@ package android.test { method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object); } - public class AndroidTestCase extends junit.framework.TestCase { + public deprecated class AndroidTestCase extends junit.framework.TestCase { ctor public AndroidTestCase(); method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String); method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String); @@ -39486,7 +39651,7 @@ package android.test { field protected android.content.Context mContext; } - public class AndroidTestRunner extends junit.runner.BaseTestRunner { + public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner { ctor public AndroidTestRunner(); method public void addTestListener(junit.framework.TestListener); method public void clearTestListeners(); @@ -39507,7 +39672,7 @@ package android.test { method public void testStarted(java.lang.String); } - public abstract class ApplicationTestCase extends android.test.AndroidTestCase { + public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase { ctor public ApplicationTestCase(java.lang.Class<T>); method protected final void createApplication(); method public T getApplication(); @@ -39525,10 +39690,10 @@ package android.test { ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String); } - public abstract class FlakyTest implements java.lang.annotation.Annotation { + public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation { } - public class InstrumentationTestCase extends junit.framework.TestCase { + public deprecated class InstrumentationTestCase extends junit.framework.TestCase { ctor public InstrumentationTestCase(); method public android.app.Instrumentation getInstrumentation(); method public deprecated void injectInsrumentation(android.app.Instrumentation); @@ -39541,7 +39706,7 @@ package android.test { method public void sendRepeatedKeys(int...); } - public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider { + public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider { ctor public InstrumentationTestRunner(); method public junit.framework.TestSuite getAllTests(); method protected android.test.AndroidTestRunner getAndroidTestRunner(); @@ -39560,14 +39725,14 @@ package android.test { field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1 } - public class InstrumentationTestSuite extends junit.framework.TestSuite { + public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite { ctor public InstrumentationTestSuite(android.app.Instrumentation); ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation); ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation); method public void addTestSuite(java.lang.Class); } - public class IsolatedContext extends android.content.ContextWrapper { + public deprecated class IsolatedContext extends android.content.ContextWrapper { ctor public IsolatedContext(android.content.ContentResolver, android.content.Context); method public java.util.List<android.content.Intent> getAndClearBroadcastIntents(); } @@ -39577,7 +39742,7 @@ package android.test { method public T getLoaderResultSynchronously(android.content.Loader<T>); } - public final class MoreAsserts { + public final deprecated class MoreAsserts { method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object); method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>); method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String); @@ -39616,7 +39781,7 @@ package android.test { method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean); } - public abstract interface PerformanceTestCase { + public abstract deprecated interface PerformanceTestCase { method public abstract boolean isPerformanceOnly(); method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates); } @@ -39645,7 +39810,7 @@ package android.test { method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException; } - public class RenamingDelegatingContext extends android.content.ContextWrapper { + public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper { ctor public RenamingDelegatingContext(android.content.Context, java.lang.String); ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String); method public java.lang.String getDatabasePrefix(); @@ -39654,7 +39819,7 @@ package android.test { method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException; } - public abstract class ServiceTestCase extends android.test.AndroidTestCase { + public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase { ctor public ServiceTestCase(java.lang.Class<T>); method protected android.os.IBinder bindService(android.content.Intent); method public android.app.Application getApplication(); @@ -39667,23 +39832,23 @@ package android.test { method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception; } - public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase { + public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase { ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>); method public T getActivity(); method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception; } - public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase { + public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase { ctor public SyncBaseInstrumentation(); method protected void cancelSyncsandDisableAutoSync(); method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception; } - public abstract interface TestSuiteProvider { + public abstract deprecated interface TestSuiteProvider { method public abstract junit.framework.TestSuite getTestSuite(); } - public class TouchUtils { + public deprecated class TouchUtils { ctor public TouchUtils(); method public static void clickView(android.test.InstrumentationTestCase, android.view.View); method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int); @@ -39718,10 +39883,10 @@ package android.test { method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View); } - public abstract class UiThreadTest implements java.lang.annotation.Annotation { + public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation { } - public class ViewAsserts { + public deprecated class ViewAsserts { method public static void assertBaselineAligned(android.view.View, android.view.View); method public static void assertBottomAligned(android.view.View, android.view.View); method public static void assertBottomAligned(android.view.View, android.view.View, int); @@ -39746,11 +39911,11 @@ package android.test { package android.test.mock { - public class MockApplication extends android.app.Application { + public deprecated class MockApplication extends android.app.Application { ctor public MockApplication(); } - public class MockContentProvider extends android.content.ContentProvider { + public deprecated class MockContentProvider extends android.content.ContentProvider { ctor protected MockContentProvider(); ctor public MockContentProvider(android.content.Context); ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]); @@ -39762,13 +39927,13 @@ package android.test.mock { method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); } - public class MockContentResolver extends android.content.ContentResolver { + public deprecated class MockContentResolver extends android.content.ContentResolver { ctor public MockContentResolver(); ctor public MockContentResolver(android.content.Context); method public void addProvider(java.lang.String, android.content.ContentProvider); } - public class MockContext extends android.content.Context { + public deprecated class MockContext extends android.content.Context { ctor public MockContext(); method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int); method public int checkCallingOrSelfPermission(java.lang.String); @@ -39872,7 +40037,7 @@ package android.test.mock { method public void unregisterReceiver(android.content.BroadcastReceiver); } - public class MockCursor implements android.database.Cursor { + public deprecated class MockCursor implements android.database.Cursor { ctor public MockCursor(); method public void close(); method public void copyStringToBuffer(int, android.database.CharArrayBuffer); @@ -39917,13 +40082,13 @@ package android.test.mock { method public void unregisterDataSetObserver(android.database.DataSetObserver); } - public class MockDialogInterface implements android.content.DialogInterface { + public deprecated class MockDialogInterface implements android.content.DialogInterface { ctor public MockDialogInterface(); method public void cancel(); method public void dismiss(); } - public class MockPackageManager extends android.content.pm.PackageManager { + public deprecated class MockPackageManager extends android.content.pm.PackageManager { ctor public MockPackageManager(); method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public void addPackageToPreferred(java.lang.String); @@ -40017,7 +40182,7 @@ package android.test.mock { method public void verifyPendingInstall(int, int); } - public class MockResources extends android.content.res.Resources { + public deprecated class MockResources extends android.content.res.Resources { ctor public MockResources(); } @@ -40058,19 +40223,19 @@ package android.test.suitebuilder { package android.test.suitebuilder.annotation { - public abstract class LargeTest implements java.lang.annotation.Annotation { + public abstract deprecated class LargeTest implements java.lang.annotation.Annotation { } - public abstract class MediumTest implements java.lang.annotation.Annotation { + public abstract deprecated class MediumTest implements java.lang.annotation.Annotation { } - public abstract class SmallTest implements java.lang.annotation.Annotation { + public abstract deprecated class SmallTest implements java.lang.annotation.Annotation { } - public abstract class Smoke implements java.lang.annotation.Annotation { + public abstract deprecated class Smoke implements java.lang.annotation.Annotation { } - public abstract class Suppress implements java.lang.annotation.Annotation { + public abstract deprecated class Suppress implements java.lang.annotation.Annotation { } } @@ -53905,6 +54070,9 @@ package java.lang.annotation { 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-removed.txt b/api/system-removed.txt index 90a5dc7c474f..27de91312fae 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -192,7 +192,7 @@ package android.provider { package android.test.mock { - public class MockPackageManager extends android.content.pm.PackageManager { + public deprecated class MockPackageManager extends android.content.pm.PackageManager { method public deprecated java.lang.String getDefaultBrowserPackageName(int); method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int); } diff --git a/api/test-current.txt b/api/test-current.txt index ddb7dc98fa91..d400113c7fe1 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4642,6 +4642,7 @@ package android.app { method public android.content.Context getContext(); method public android.content.Context getTargetContext(); method public android.app.UiAutomation getUiAutomation(); + method public android.app.UiAutomation getUiAutomation(int); method public boolean invokeContextMenuAction(android.app.Activity, int, int); method public boolean invokeMenuActionSync(android.app.Activity, int, int); method public boolean isProfiling(); @@ -5538,6 +5539,7 @@ package android.app { public final class UiAutomation { method public void clearWindowAnimationFrameStats(); method public boolean clearWindowContentFrameStats(int); + method public void destroy(); method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException; method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); @@ -5556,6 +5558,7 @@ package android.app { 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 +5826,7 @@ package android.app.admin { 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 +5896,7 @@ package android.app.admin { 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); @@ -19880,6 +19885,7 @@ package android.media { 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 +19957,8 @@ package android.media { 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 +22513,7 @@ package android.media.session { 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 +22592,7 @@ package android.media.session { 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 +22909,7 @@ package android.media.tv { method public void onInputAdded(java.lang.String); method public void onInputRemoved(java.lang.String); method public void onInputStateChanged(java.lang.String, int); - method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo); + method public void onTvInputInfoChanged(android.media.tv.TvInputInfo); } public abstract class TvInputService extends android.app.Service { @@ -22907,7 +22917,7 @@ package android.media.tv { method public final android.os.IBinder onBind(android.content.Intent); method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String); method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String); - method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo); + method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo); field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService"; field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input"; } @@ -28545,6 +28555,10 @@ package android.os { 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 +29150,7 @@ package android.os { 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 +29617,8 @@ package android.preference { 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 +32072,7 @@ package android.provider { 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"; @@ -37201,7 +37219,7 @@ package android.test { method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception; } - public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase { + public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase { ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>); ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>); method public T getActivity(); @@ -37209,14 +37227,14 @@ package android.test { method public void setActivityIntent(android.content.Intent); } - public abstract class ActivityTestCase extends android.test.InstrumentationTestCase { + public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase { ctor public ActivityTestCase(); method protected android.app.Activity getActivity(); method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException; method protected void setActivity(android.app.Activity); } - public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase { + public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase { ctor public ActivityUnitTestCase(java.lang.Class<T>); method public T getActivity(); method public int getFinishedActivityRequest(); @@ -37229,7 +37247,7 @@ package android.test { method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object); } - public class AndroidTestCase extends junit.framework.TestCase { + public deprecated class AndroidTestCase extends junit.framework.TestCase { ctor public AndroidTestCase(); method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String); method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String); @@ -37241,7 +37259,7 @@ package android.test { field protected android.content.Context mContext; } - public class AndroidTestRunner extends junit.runner.BaseTestRunner { + public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner { ctor public AndroidTestRunner(); method public void addTestListener(junit.framework.TestListener); method public void clearTestListeners(); @@ -37262,7 +37280,7 @@ package android.test { method public void testStarted(java.lang.String); } - public abstract class ApplicationTestCase extends android.test.AndroidTestCase { + public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase { ctor public ApplicationTestCase(java.lang.Class<T>); method protected final void createApplication(); method public T getApplication(); @@ -37280,10 +37298,10 @@ package android.test { ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String); } - public abstract class FlakyTest implements java.lang.annotation.Annotation { + public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation { } - public class InstrumentationTestCase extends junit.framework.TestCase { + public deprecated class InstrumentationTestCase extends junit.framework.TestCase { ctor public InstrumentationTestCase(); method public android.app.Instrumentation getInstrumentation(); method public deprecated void injectInsrumentation(android.app.Instrumentation); @@ -37296,7 +37314,7 @@ package android.test { method public void sendRepeatedKeys(int...); } - public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider { + public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider { ctor public InstrumentationTestRunner(); method public junit.framework.TestSuite getAllTests(); method protected android.test.AndroidTestRunner getAndroidTestRunner(); @@ -37315,14 +37333,14 @@ package android.test { field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1 } - public class InstrumentationTestSuite extends junit.framework.TestSuite { + public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite { ctor public InstrumentationTestSuite(android.app.Instrumentation); ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation); ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation); method public void addTestSuite(java.lang.Class); } - public class IsolatedContext extends android.content.ContextWrapper { + public deprecated class IsolatedContext extends android.content.ContextWrapper { ctor public IsolatedContext(android.content.ContentResolver, android.content.Context); method public java.util.List<android.content.Intent> getAndClearBroadcastIntents(); } @@ -37332,7 +37350,7 @@ package android.test { method public T getLoaderResultSynchronously(android.content.Loader<T>); } - public final class MoreAsserts { + public final deprecated class MoreAsserts { method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object); method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>); method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String); @@ -37371,7 +37389,7 @@ package android.test { method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean); } - public abstract interface PerformanceTestCase { + public abstract deprecated interface PerformanceTestCase { method public abstract boolean isPerformanceOnly(); method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates); } @@ -37400,7 +37418,7 @@ package android.test { method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException; } - public class RenamingDelegatingContext extends android.content.ContextWrapper { + public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper { ctor public RenamingDelegatingContext(android.content.Context, java.lang.String); ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String); method public java.lang.String getDatabasePrefix(); @@ -37409,7 +37427,7 @@ package android.test { method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException; } - public abstract class ServiceTestCase extends android.test.AndroidTestCase { + public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase { ctor public ServiceTestCase(java.lang.Class<T>); method protected android.os.IBinder bindService(android.content.Intent); method public android.app.Application getApplication(); @@ -37422,23 +37440,23 @@ package android.test { method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception; } - public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase { + public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase { ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>); method public T getActivity(); method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception; } - public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase { + public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase { ctor public SyncBaseInstrumentation(); method protected void cancelSyncsandDisableAutoSync(); method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception; } - public abstract interface TestSuiteProvider { + public abstract deprecated interface TestSuiteProvider { method public abstract junit.framework.TestSuite getTestSuite(); } - public class TouchUtils { + public deprecated class TouchUtils { ctor public TouchUtils(); method public static void clickView(android.test.InstrumentationTestCase, android.view.View); method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int); @@ -37473,10 +37491,10 @@ package android.test { method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View); } - public abstract class UiThreadTest implements java.lang.annotation.Annotation { + public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation { } - public class ViewAsserts { + public deprecated class ViewAsserts { method public static void assertBaselineAligned(android.view.View, android.view.View); method public static void assertBottomAligned(android.view.View, android.view.View); method public static void assertBottomAligned(android.view.View, android.view.View, int); @@ -37501,11 +37519,11 @@ package android.test { package android.test.mock { - public class MockApplication extends android.app.Application { + public deprecated class MockApplication extends android.app.Application { ctor public MockApplication(); } - public class MockContentProvider extends android.content.ContentProvider { + public deprecated class MockContentProvider extends android.content.ContentProvider { ctor protected MockContentProvider(); ctor public MockContentProvider(android.content.Context); ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]); @@ -37517,13 +37535,13 @@ package android.test.mock { method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); } - public class MockContentResolver extends android.content.ContentResolver { + public deprecated class MockContentResolver extends android.content.ContentResolver { ctor public MockContentResolver(); ctor public MockContentResolver(android.content.Context); method public void addProvider(java.lang.String, android.content.ContentProvider); } - public class MockContext extends android.content.Context { + public deprecated class MockContext extends android.content.Context { ctor public MockContext(); method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int); method public int checkCallingOrSelfPermission(java.lang.String); @@ -37624,7 +37642,7 @@ package android.test.mock { method public void unregisterReceiver(android.content.BroadcastReceiver); } - public class MockCursor implements android.database.Cursor { + public deprecated class MockCursor implements android.database.Cursor { ctor public MockCursor(); method public void close(); method public void copyStringToBuffer(int, android.database.CharArrayBuffer); @@ -37669,13 +37687,13 @@ package android.test.mock { method public void unregisterDataSetObserver(android.database.DataSetObserver); } - public class MockDialogInterface implements android.content.DialogInterface { + public deprecated class MockDialogInterface implements android.content.DialogInterface { ctor public MockDialogInterface(); method public void cancel(); method public void dismiss(); } - public class MockPackageManager extends android.content.pm.PackageManager { + public deprecated class MockPackageManager extends android.content.pm.PackageManager { ctor public MockPackageManager(); method public void addPackageToPreferred(java.lang.String); method public boolean addPermission(android.content.pm.PermissionInfo); @@ -37763,7 +37781,7 @@ package android.test.mock { method public void verifyPendingInstall(int, int); } - public class MockResources extends android.content.res.Resources { + public deprecated class MockResources extends android.content.res.Resources { ctor public MockResources(); } @@ -37804,19 +37822,19 @@ package android.test.suitebuilder { package android.test.suitebuilder.annotation { - public abstract class LargeTest implements java.lang.annotation.Annotation { + public abstract deprecated class LargeTest implements java.lang.annotation.Annotation { } - public abstract class MediumTest implements java.lang.annotation.Annotation { + public abstract deprecated class MediumTest implements java.lang.annotation.Annotation { } - public abstract class SmallTest implements java.lang.annotation.Annotation { + public abstract deprecated class SmallTest implements java.lang.annotation.Annotation { } - public abstract class Smoke implements java.lang.annotation.Annotation { + public abstract deprecated class Smoke implements java.lang.annotation.Annotation { } - public abstract class Suppress implements java.lang.annotation.Annotation { + public abstract deprecated class Suppress implements java.lang.annotation.Annotation { } } @@ -51315,6 +51333,9 @@ package java.lang.annotation { 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-removed.txt b/api/test-removed.txt index 6b7961e9f1f6..2c6729d2c159 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -201,7 +201,7 @@ package android.provider { package android.test.mock { - public class MockPackageManager extends android.content.pm.PackageManager { + public deprecated class MockPackageManager extends android.content.pm.PackageManager { method public deprecated java.lang.String getDefaultBrowserPackageName(int); method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int); } diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 72e8c3b61027..d45bc5dc8789 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -47,7 +47,6 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; -import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -79,7 +78,6 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.List; public class Am extends BaseCommand { @@ -159,6 +157,7 @@ public class Am extends BaseCommand { " am stack start <DISPLAY_ID> <INTENT>\n" + " am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" + " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + + " am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + " am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" + " am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" + " am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + @@ -1688,6 +1687,9 @@ public class Am extends BaseCommand { case "resize": runStackResize(); break; + case "resize-animated": + runStackResizeAnimated(); + break; case "resize-docked-stack": runStackResizeDocked(); break; @@ -1756,7 +1758,18 @@ public class Am extends BaseCommand { System.err.println("Error: invalid input bounds"); return; } - resizeStack(stackId, bounds, 0); + resizeStack(stackId, bounds, 0, false); + } + + private void runStackResizeAnimated() throws Exception { + String stackIdStr = nextArgRequired(); + int stackId = Integer.valueOf(stackIdStr); + final Rect bounds = getBounds(); + if (bounds == null) { + System.err.println("Error: invalid input bounds"); + return; + } + resizeStack(stackId, bounds, 0, true); } private void runStackResizeDocked() throws Exception { @@ -1773,14 +1786,15 @@ public class Am extends BaseCommand { } } - private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception { + private void resizeStack(int stackId, Rect bounds, int delayMs, boolean animate) + throws Exception { if (bounds == null) { showError("Error: invalid input bounds"); return; } try { - mAm.resizeStack(stackId, bounds, false); + mAm.resizeStack(stackId, bounds, false, false, animate); Thread.sleep(delayMs); } catch (RemoteException e) { showError("Error: resizing stack " + e); @@ -1894,7 +1908,7 @@ public class Am extends BaseCommand { maxChange = Math.min(stepSize, currentPoint - minPoint); currentPoint -= maxChange; setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs); + resizeStack(DOCKED_STACK_ID, bounds, delayMs, false); } System.out.println("Growing docked stack side=" + side); @@ -1902,7 +1916,7 @@ public class Am extends BaseCommand { maxChange = Math.min(stepSize, maxPoint - currentPoint); currentPoint += maxChange; setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs); + resizeStack(DOCKED_STACK_ID, bounds, delayMs, false); } System.out.println("Back to Original size side=" + side); @@ -1910,7 +1924,7 @@ public class Am extends BaseCommand { maxChange = Math.min(stepSize, currentPoint - startPoint); currentPoint -= maxChange; setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs); + resizeStack(DOCKED_STACK_ID, bounds, delayMs, false); } } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 8bc17f8d15eb..be939264c7e9 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -49,7 +49,8 @@ import com.android.internal.os.SomeArgs; 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 +67,31 @@ import java.util.List; * <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 +145,24 @@ import java.util.List; * </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 +314,6 @@ public abstract class AccessibilityService extends Service { * android:settingsActivity="foo.bar.TestBackActivity" * android:canRetrieveWindowContent="true" * android:canRequestTouchExplorationMode="true" - * android:canRequestEnhancedWebAccessibility="true" * . . . * /></pre> */ @@ -528,6 +513,14 @@ public abstract class AccessibilityService extends Service { * 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 +534,8 @@ public abstract class AccessibilityService extends Service { } /** - * 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 = @@ -1054,7 +1047,7 @@ public abstract class AccessibilityService extends Service { * 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 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 11154f2ac9ea..dc3f64ab270e 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4397,7 +4397,7 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper @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 @@ public class Activity extends ContextThemeWrapper 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/ActivityManager.java b/core/java/android/app/ActivityManager.java index 420bf31a189d..90feab4327b7 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -564,8 +564,7 @@ public class ActivityManager { * there isn't a display gap. */ public static boolean preserveWindowOnTaskMove(int stackId) { - return stackId == FULLSCREEN_WORKSPACE_STACK_ID - || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID; + return stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID; } /** @@ -616,6 +615,14 @@ public class ActivityManager { public static boolean keepVisibleDeadAppWindowOnScreen(int stackId) { return stackId != PINNED_STACK_ID; } + + /** + * Returns true if the backdrop on the client side should match the frame of the window. + * Returns false, if the backdrop should be fullscreen. + */ + public static boolean useWindowFrameForBackdrop(int stackId) { + return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID; + } } /** diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 42ff8e83862d..cd5797ecb286 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -816,7 +816,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM r = Rect.CREATOR.createFromParcel(data); } final boolean allowResizeInDockedMode = data.readInt() == 1; - resizeStack(stackId, r, allowResizeInDockedMode); + final boolean preserveWindows = data.readInt() == 1; + final boolean animate = data.readInt() == 1; + resizeStack(stackId, r, allowResizeInDockedMode, preserveWindows, animate); reply.writeNoException(); return true; } @@ -3815,9 +3817,8 @@ class ActivityManagerProxy implements IActivityManager return res; } @Override - public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode) - throws RemoteException - { + public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode, + boolean preserveWindows, boolean animate) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -3829,6 +3830,8 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(0); } data.writeInt(allowResizeInDockedMode ? 1 : 0); + data.writeInt(preserveWindows ? 1 : 0); + data.writeInt(animate ? 1 : 0); mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1e7457cdd551..100e67badb43 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -56,6 +56,7 @@ import android.net.Uri; import android.opengl.GLUtils; import android.os.AsyncTask; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.DropBoxManager; @@ -4959,16 +4960,22 @@ public final class ActivityThread { } /** - * 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 fab3740610e6..0d6e93d1717a 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -752,7 +752,7 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { } 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { } 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { < 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/IActivityManager.java b/core/java/android/app/IActivityManager.java index 22de2ff7bc6e..5b3ffe05451a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -146,8 +146,8 @@ public interface IActivityManager extends IInterface { public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds) throws RemoteException; public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException; - public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) - throws RemoteException; + public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode, + boolean preserveWindows, boolean animate) throws RemoteException; /** * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change. diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 2caec36911f1..7640e75ba153 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -33,7 +33,7 @@ import android.os.ParcelFileDescriptor; * {@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 7a0e7f616295..fa0fbd1cb8fa 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -35,10 +35,16 @@ interface IWallpaperManager { * '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 @@ interface IWallpaperManager { */ 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 24a347068b73..9a88f2c67697 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1503,7 +1503,7 @@ public class Instrumentation { } 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 @@ public class Instrumentation { 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 @@ public class Instrumentation { } 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 @@ public class Instrumentation { } 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 @@ public class Instrumentation { } 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 @@ public class Instrumentation { } 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 @@ public class Instrumentation { * {@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 @@ public class Instrumentation { 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 0f3aad9c56fa..7f037f22aa8d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -4384,7 +4384,17 @@ public class Notification implements Parcelable 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 edafe59ca454..412b098a5872 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -307,7 +307,7 @@ public final class PendingIntent implements Parcelable { 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 @@ public final class PendingIntent implements Parcelable { 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 @@ public final class PendingIntent implements Parcelable { 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 @@ public final class PendingIntent implements Parcelable { 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 @@ public final class PendingIntent implements Parcelable { 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 @@ public final class PendingIntent implements Parcelable { 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 dce2e518d1e0..79d383c53cf6 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -105,6 +105,14 @@ public final class UiAutomation { /** 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 @@ public final class UiAutomation { private boolean mIsConnecting; + private boolean mIsDestroyed; + + private int mFlags; + /** * Listener for observing the {@link AccessibilityEvent} stream. */ @@ -182,11 +194,22 @@ public final class UiAutomation { } /** - * 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 @@ public final class UiAutomation { 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 @@ public final class UiAutomation { } /** + * 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 @@ public final class UiAutomation { } /** + * 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 @@ public final class UiAutomation { } /** + * Destroy this UiAutomation. After calling this method, attempting to use the object will + * result in errors. + */ + public void destroy() { + disconnect(); + mIsDestroyed = true; + } + + /** * Performs a global action. Such an action can be performed at any moment * regardless of the current application or user location in that application. * For example going back, going home, opening recents, etc. diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index bd10267bc0f5..276f774a8f4e 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -77,7 +77,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { 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 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { throw new IllegalStateException("Already connected."); } mOwningUid = Binder.getCallingUid(); - registerUiTestAutomationServiceLocked(client); + registerUiTestAutomationServiceLocked(client, flags); storeRotationStateLocked(); } } @@ -322,7 +322,8 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } } - 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 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { 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 f1035767ad7b..b0ffd21b2c98 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -64,6 +64,8 @@ import java.io.InputStream; 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 @@ public class WallpaperManager { 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 @@ public class WallpaperManager { 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 @@ public class WallpaperManager { 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 @@ public class WallpaperManager { 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 a3c615db7eb3..c79c4072e745 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -30,6 +30,7 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.graphics.Bitmap; import android.net.ProxyInfo; import android.net.Uri; @@ -3345,6 +3346,10 @@ public class DevicePolicyManager { * <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. @@ -5210,6 +5215,10 @@ public class DevicePolicyManager { * 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. @@ -5249,6 +5258,10 @@ public class DevicePolicyManager { * 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. @@ -5346,6 +5359,22 @@ public class DevicePolicyManager { } /** + * Called by the system to obtain a {@link DevicePolicyManager} whose calls act on the parent + * profile. + * + * @hide + */ + public DevicePolicyManager getParentProfileInstance(UserInfo uInfo) { + mContext.checkSelfPermission( + android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + if (!uInfo.isManagedProfile()) { + throw new SecurityException("The user " + uInfo.id + + " does not have a parent profile."); + } + return new DevicePolicyManager(mContext, true); + } + + /** * Called by a profile owner of a managed profile to set the color used for customization. * This color is used as background color of the confirm credentials screen for that user. * The default color is {@link android.graphics.Color#GRAY}. @@ -5397,6 +5426,58 @@ public class DevicePolicyManager { } /** + * 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 6333013612db..37d13e54b826 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -276,6 +276,10 @@ interface IDevicePolicyManager { 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/UsageStats.java b/core/java/android/app/usage/UsageStats.java index 0fce4e2cd184..a88aa312550d 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -165,14 +165,18 @@ public final class UsageStats implements Parcelable { 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 2260d7e07e03..10e6fb233249 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -522,7 +522,7 @@ public abstract class BroadcastReceiver { 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 6dfefacb2cb4..0ec58ea40fe4 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -823,14 +823,14 @@ public class ClipData implements Parcelable { * * @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 5653cadfa44c..e67da2bfe7f8 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -118,7 +118,7 @@ public class ClipboardManager extends android.text.ClipboardManager { 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 49b836318f5c..ee469dabcf43 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -8912,23 +8912,46 @@ public class Intent implements Parcelable, Cloneable { * * @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(); - } - - 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()"); + mClipData.prepareToLeaveProcess(leavingPackage); + } + + 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/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index 1d165168db53..7f9e17641a19 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -30,8 +30,7 @@ import java.util.Set; * when they are committed to storage. Objects that are returned from the * various <code>get</code> methods must be treated as immutable by the application. * - * <p><em>Note: currently this class does not support use across multiple - * processes. This will be added later.</em> + * <p><em>Note: This class does not support use across multiple processes.</em> * * <div class="special reference"> * <h3>Developer Guides</h3> diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index dedf07f5dcff..91a8e0a96191 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -156,6 +156,35 @@ public class ActivityInfo extends ComponentInfo public String targetActivity; /** + * Activity can not be resized and always occupies the fullscreen area with all windows fully + * visible. + * @hide + */ + public static final int RESIZE_MODE_UNRESIZEABLE = 0; + /** + * Activity can not be resized and always occupies the fullscreen area with all windows cropped + * to either the task or stack bounds. + * @hide + */ + public static final int RESIZE_MODE_CROP_WINDOWS = 1; + /** + * Activity is resizeable. + * @hide + */ + public static final int RESIZE_MODE_RESIZEABLE = 2; + /** + * Activity is resizeable and supported picture-in-picture mode. + * @hide + */ + public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3; + /** + * Value indicating if the resizing mode the activity supports. + * See {@link android.R.attr#resizeableActivity}. + * @hide + */ + public int resizeMode; + + /** * Bit in {@link #flags} indicating whether this activity is able to * run in multiple processes. If * true, the system may instantiate it in the some process as the @@ -283,20 +312,6 @@ public class ActivityInfo extends ComponentInfo public static final int FLAG_ENABLE_VR_MODE = 0x8000; /** - * Bit in {@link #flags} indicating if the activity is resizeable to any dimension. - * See {@link android.R.attr#resizeableActivity}. - * @hide - */ - public static final int FLAG_RESIZEABLE = 0x10000; - - /** - * Bit in {@link #flags} indicating if the activity is supports picture-in-picture form of - * multi-window mode. See {@link android.R.attr#supportsPictureInPicture}. - * @hide - */ - public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x20000; - - /** * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is * in a task/stack whose activities are normally not focusable. * See android.R.attr#alwaysFocusable. @@ -746,6 +761,7 @@ public class ActivityInfo extends ComponentInfo maxRecents = orig.maxRecents; lockTaskLaunchMode = orig.lockTaskLaunchMode; layout = orig.layout; + resizeMode = orig.resizeMode; } /** @@ -768,6 +784,22 @@ public class ActivityInfo extends ComponentInfo } } + /** @hide */ + public static final String resizeModeToString(int mode) { + switch (mode) { + case RESIZE_MODE_UNRESIZEABLE: + return "RESIZE_MODE_UNRESIZEABLE"; + case RESIZE_MODE_CROP_WINDOWS: + return "RESIZE_MODE_CROP_WINDOWS"; + case RESIZE_MODE_RESIZEABLE: + return "RESIZE_MODE_RESIZEABLE"; + case RESIZE_MODE_RESIZEABLE_AND_PIPABLE: + return "RESIZE_MODE_RESIZEABLE_AND_PIPABLE"; + default: + return "unknown=" + mode; + } + } + public void dump(Printer pw, String prefix) { dump(pw, prefix, DUMP_FLAG_ALL); } @@ -806,6 +838,7 @@ public class ActivityInfo extends ComponentInfo + layout.widthFraction + ", " + layout.height + "|" + layout.heightFraction + ", " + layout.gravity); } + pw.println(prefix + "resizeMode=" + resizeModeToString(resizeMode)); super.dumpBack(pw, prefix, flags); } @@ -847,6 +880,7 @@ public class ActivityInfo extends ComponentInfo } else { dest.writeInt(0); } + dest.writeInt(resizeMode); } public static final Parcelable.Creator<ActivityInfo> CREATOR @@ -879,6 +913,7 @@ public class ActivityInfo extends ComponentInfo if (source.readInt() == 1) { layout = new Layout(source); } + resizeMode = source.readInt(); } public static final class Layout { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 476dc46a2118..3a94bf723912 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2017,6 +2017,11 @@ public abstract class PackageManager { public static final String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users"; + /** {@hide} */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_FILE_BASED_ENCRYPTION + = "android.software.file_based_encryption"; + /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * The device has a full implementation of the android.webkit.* APIs. Devices @@ -3627,7 +3632,7 @@ public abstract class PackageManager { * {@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 @@ -3648,9 +3653,19 @@ public abstract class PackageManager { * * @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 a6fec9f3f67b..44cd0039dc09 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -16,15 +16,12 @@ package android.content.pm; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import com.android.internal.R; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import android.app.ActivityManager; import android.content.ComponentName; @@ -55,15 +52,6 @@ import android.util.apk.ApkSignatureSchemeV2Verifier; import android.util.jar.StrictJarFile; import android.view.Gravity; -import com.android.internal.R; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.XmlUtils; - -import libcore.io.IoUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -87,6 +75,25 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.ZipEntry; +import libcore.io.IoUtils; + +import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + /** * Parser for package files (APKs) on disk. This supports apps packaged either * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple @@ -3219,24 +3226,29 @@ public class PackageParser { a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; } - if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, - owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) { - a.info.flags |= ActivityInfo.FLAG_RESIZEABLE; - - if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, - false)) { - a.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; + a.info.screenOrientation = sa.getInt( + R.styleable.AndroidManifestActivity_screenOrientation, + SCREEN_ORIENTATION_UNSPECIFIED); + + a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; + if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) { + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, true)) { + if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, + false)) { + a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE; + } else { + a.info.resizeMode = RESIZE_MODE_RESIZEABLE; + } } + } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED + && (a.info.flags & FLAG_IMMERSIVE) == 0) { + a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS; } if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { - a.info.flags |= ActivityInfo.FLAG_ALWAYS_FOCUSABLE; + a.info.flags |= FLAG_ALWAYS_FOCUSABLE; } - a.info.screenOrientation = sa.getInt( - R.styleable.AndroidManifestActivity_screenOrientation, - ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - a.info.lockTaskLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); @@ -3478,6 +3490,8 @@ public class PackageParser { info.parentActivityName = target.info.parentActivityName; 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 584008c1db33..2cafa088665a 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 @@ public final class KeyboardLayout implements Parcelable, 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 final class KeyboardLayout implements Parcelable, }; 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 @@ public final class KeyboardLayout implements Parcelable, 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 @@ public final class KeyboardLayout implements Parcelable, * 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 @@ public final class KeyboardLayout implements Parcelable, 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 000000000000..1a9221a02cc3 --- /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 000000000000..e47c541ee62b --- /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 000000000000..301b2e49a19c --- /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 000000000000..915f1ec683c9 --- /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 000000000000..954e97dc7fce --- /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 000000000000..a2a13c6f8289 --- /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 000000000000..45b1ef494ac2 --- /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 000000000000..b2db0b2cdd23 --- /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 000000000000..e8c761527c2c --- /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 000000000000..d32c44a5c44a --- /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 000000000000..36d181f91fba --- /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 000000000000..cc6d4755997a --- /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 000000000000..ac341e417b64 --- /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 000000000000..c8c40d7be233 --- /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 000000000000..ac62919b7931 --- /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/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 3bd12c060748..e27c0fb2ddea 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -197,6 +197,19 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_CAPTIVE_PORTAL); /** + * Network specifier for factories which want to match any network specifier + * (NS) in a request. Behavior: + * <li>Empty NS in request matches any network factory NS</li> + * <li>Empty NS in the network factory NS only matches a request with an + * empty NS</li> + * <li>"*" (this constant) NS in the network factory matches requests with + * any NS</li> + * + * @hide + */ + public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*"; + + /** * Network capabilities that are not allowed in NetworkRequests. This exists because the * NetworkFactory / NetworkAgent model does not deal well with the situation where a * capability's presence cannot be known in advance. If such a capability is requested, then we @@ -596,7 +609,8 @@ public final class NetworkCapabilities implements Parcelable { } private boolean satisfiedBySpecifier(NetworkCapabilities nc) { return (TextUtils.isEmpty(mNetworkSpecifier) || - mNetworkSpecifier.equals(nc.mNetworkSpecifier)); + mNetworkSpecifier.equals(nc.mNetworkSpecifier) || + MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier)); } private boolean equalsSpecifier(NetworkCapabilities nc) { if (TextUtils.isEmpty(mNetworkSpecifier)) { diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 7da4818991b6..f1edcbe30df6 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -188,6 +188,10 @@ public class NetworkRequest implements Parcelable { * networks. */ public Builder setNetworkSpecifier(String networkSpecifier) { + if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) { + throw new IllegalArgumentException("Invalid network specifier - must not be '" + + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'"); + } mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); return this; } diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 4a8dfbc5aefe..53b027b1888b 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -2343,7 +2343,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { */ 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 000000000000..e47abe288d22 --- /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 f1672df15109..91d88da8b733 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -24,6 +24,7 @@ import android.content.BroadcastReceiver; 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.net.UnknownHostException; 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 @@ public final class StrictMode { // 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 final class StrictMode { */ 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 @@ public final class StrictMode { * 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 @@ public final class StrictMode { } /** - * 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 @@ public final class StrictMode { } /** + * 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 @@ public final class StrictMode { } /** + * 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 @@ public final class StrictMode { /** * @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 bcc12139b5e4..344d06ec3143 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -144,6 +144,7 @@ public final class UserHandle implements Parcelable { } /** @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 6321122c6837..1ac798b82f4a 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1382,7 +1382,7 @@ public class UserManager { /** * 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 @@ public class UserManager { } /** + * 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 fda632689c28..ebb12fd1291d 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.Intent; 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 @@ public class PreferenceManager { * 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 @@ public class PreferenceManager { } /** + * 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 class PreferenceManager { */ 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 bc0d7d6b31eb..c9c0cdeff17c 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -501,6 +501,23 @@ public final class Settings { "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 diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 0c6a0c6e1d26..6ff9fe74859d 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -1170,7 +1170,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } 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/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java index 2ecbfae6fede..1e6bd9c14fd9 100644 --- a/core/java/android/test/AndroidTestCase.java +++ b/core/java/android/test/AndroidTestCase.java @@ -29,7 +29,13 @@ import java.lang.reflect.Modifier; /** * Extend this if you need to access Resources or other things that depend on Activity Context. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html"> + * InstrumentationRegistry</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class AndroidTestCase extends TestCase { protected Context mContext; diff --git a/core/java/android/test/FlakyTest.java b/core/java/android/test/FlakyTest.java index 919767f9e999..4e5c4e35a8c6 100644 --- a/core/java/android/test/FlakyTest.java +++ b/core/java/android/test/FlakyTest.java @@ -26,7 +26,13 @@ import java.lang.annotation.ElementType; * test methods. When the annotation is present, the test method is re-executed if * the test fails. The total number of executions is specified by the tolerance and * defaults to 1. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/filters/FlakyTest.html"> + * FlakyTest</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface FlakyTest { diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java index ca427ea6a4c5..6b79314a4385 100644 --- a/core/java/android/test/InstrumentationTestCase.java +++ b/core/java/android/test/InstrumentationTestCase.java @@ -32,7 +32,13 @@ import junit.framework.TestCase; /** * A test case that has access to {@link Instrumentation}. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html"> + * InstrumentationRegistry</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class InstrumentationTestCase extends TestCase { private Instrumentation mInstrumentation; @@ -40,7 +46,7 @@ public class InstrumentationTestCase extends TestCase { /** * Injects instrumentation into this test case. This method is * called by the test runner during test setup. - * + * * @param instrumentation the instrumentation to use with this instance */ public void injectInstrumentation(Instrumentation instrumentation) { diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java index 7a78ffbb226d..a53fa267f1e1 100644 --- a/core/java/android/test/InstrumentationTestSuite.java +++ b/core/java/android/test/InstrumentationTestSuite.java @@ -25,7 +25,13 @@ import junit.framework.TestResult; /** * A {@link junit.framework.TestSuite} that injects {@link android.app.Instrumentation} into * {@link InstrumentationTestCase} before running them. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html"> + * InstrumentationRegistry</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class InstrumentationTestSuite extends TestSuite { private final Instrumentation mInstrumentation; diff --git a/core/java/android/test/PerformanceTestCase.java b/core/java/android/test/PerformanceTestCase.java index 679ad406c733..65bd4a48f7f5 100644 --- a/core/java/android/test/PerformanceTestCase.java +++ b/core/java/android/test/PerformanceTestCase.java @@ -18,10 +18,11 @@ package android.test; /** * More complex interface performance for test cases. - * + * * If you want your test to be used as a performance test, you must * implement this interface. */ +@Deprecated public interface PerformanceTestCase { /** @@ -37,27 +38,27 @@ public interface PerformanceTestCase } /** - * Set up to begin performance tests. The 'intermediates' is a + * Set up to begin performance tests. The 'intermediates' is a * communication channel to send back intermediate performance numbers -- * if you use it, you will probably want to ensure your test is only * executed once by returning 1. Otherwise, return 0 to allow the test * harness to decide the number of iterations. - * + * * <p>If you return a non-zero iteration count, you should call * {@link Intermediates#startTiming intermediates.startTiming} and * {@link Intermediates#finishTiming intermediates.endTiming} to report the * duration of the test whose performance should actually be measured. - * + * * @param intermediates Callback for sending intermediate results. - * + * * @return int Maximum number of iterations to run, or 0 to let the caller - * decide. + * decide. */ int startPerformance(Intermediates intermediates); - + /** * This method is used to determine what modes this test case can run in. - * + * * @return true if this test case can only be run in performance mode. */ boolean isPerformanceOnly(); diff --git a/core/java/android/test/UiThreadTest.java b/core/java/android/test/UiThreadTest.java index cd9223184da2..cd06ab890074 100644 --- a/core/java/android/test/UiThreadTest.java +++ b/core/java/android/test/UiThreadTest.java @@ -26,7 +26,13 @@ import java.lang.annotation.ElementType; * When the annotation is present, the test method is executed on the application's * main thread (or UI thread.) Note that instrumentation methods may not be used * when this annotation is present. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/annotation/UiThreadTest.html"> + * UiThreadTest</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface UiThreadTest { diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/core/java/android/test/suitebuilder/annotation/LargeTest.java index a6269e787556..dc77ee6b2739 100644 --- a/core/java/android/test/suitebuilder/annotation/LargeTest.java +++ b/core/java/android/test/suitebuilder/annotation/LargeTest.java @@ -23,7 +23,13 @@ import java.lang.annotation.Target; /** * Marks a test that should run as part of the large tests. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/filters/LargeTest.html"> + * LargeTest</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface LargeTest { diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/core/java/android/test/suitebuilder/annotation/MediumTest.java index 8afeb911d065..b941da03ac9a 100644 --- a/core/java/android/test/suitebuilder/annotation/MediumTest.java +++ b/core/java/android/test/suitebuilder/annotation/MediumTest.java @@ -24,7 +24,12 @@ import java.lang.annotation.Target; /** * Marks a test that should run as part of the medium tests. * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/filters/MediumTest.html"> + * MediumTest</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface MediumTest { diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/core/java/android/test/suitebuilder/annotation/SmallTest.java index ad530e287343..d3c74f019b53 100644 --- a/core/java/android/test/suitebuilder/annotation/SmallTest.java +++ b/core/java/android/test/suitebuilder/annotation/SmallTest.java @@ -23,7 +23,13 @@ import java.lang.annotation.Target; /** * Marks a test that should run as part of the small tests. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/filters/SmallTest.html"> + * SmallTest</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface SmallTest { diff --git a/core/java/android/test/suitebuilder/annotation/Smoke.java b/core/java/android/test/suitebuilder/annotation/Smoke.java index 237e0333b4ef..aac293796be1 100644 --- a/core/java/android/test/suitebuilder/annotation/Smoke.java +++ b/core/java/android/test/suitebuilder/annotation/Smoke.java @@ -27,7 +27,11 @@ import java.lang.annotation.Target; * will run all tests with this annotation. * * @see android.test.suitebuilder.SmokeTestSuiteBuilder + * + * @deprecated New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Smoke { diff --git a/core/java/android/test/suitebuilder/annotation/Suppress.java b/core/java/android/test/suitebuilder/annotation/Suppress.java index f16c8fafa4af..629a3cf4a2cd 100644 --- a/core/java/android/test/suitebuilder/annotation/Suppress.java +++ b/core/java/android/test/suitebuilder/annotation/Suppress.java @@ -26,7 +26,12 @@ import java.lang.annotation.ElementType; * suite. If the annotation appears on the class then no tests in that class will be included. If * the annotation appears only on a test method then only that method will be excluded. * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/filters/Suppress.html"> + * Suppress</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Suppress { diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java index 013255b9a612..57d07c0d0eac 100644 --- a/core/java/android/view/KeyboardShortcutGroup.java +++ b/core/java/android/view/KeyboardShortcutGroup.java @@ -32,6 +32,8 @@ import static com.android.internal.util.Preconditions.checkNotNull; 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 @@ public final class KeyboardShortcutGroup implements Parcelable { 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 @@ public final class KeyboardShortcutGroup implements Parcelable { return mItems; } + /** @hide **/ + public boolean isSystemGroup() { + return mSystemGroup; + } + /** * Adds an item to the existing list. * @@ -88,6 +118,7 @@ public final class KeyboardShortcutGroup implements Parcelable { 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 @@ public final class KeyboardShortcutGroup implements Parcelable { 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 1c0ea0f9120b..34713ad487fe 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -25,8 +25,6 @@ import android.widget.LinearLayout; import android.widget.RemoteViews; import android.widget.TextView; -import com.android.internal.R; - import java.util.ArrayList; /** @@ -39,6 +37,7 @@ public class NotificationHeaderView extends LinearLayout { 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 @@ public class NotificationHeaderView extends LinearLayout { private int mOriginalNotificationColor; private boolean mGroupHeader; private boolean mExpanded; + private boolean mShowWorkBadgeAtEnd; public NotificationHeaderView(Context context) { this(context, null); @@ -68,6 +68,8 @@ public class NotificationHeaderView extends LinearLayout { 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 @@ public class NotificationHeaderView extends LinearLayout { 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 @@ public class NotificationHeaderView extends LinearLayout { 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 7ba046b0ca1f..81bb638e62fb 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -139,9 +139,7 @@ public final class PointerIcon implements Parcelable { 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 @@ public final class PointerIcon implements Parcelable { } /** + * 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 772eeec880ee..0c5a5fc4bd45 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -589,14 +589,14 @@ public interface WindowManager extends ViewManager { 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 1327ea1c2f56..b67338655057 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -38,8 +38,8 @@ import java.util.List; /** * 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 @@ import java.util.List; * <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 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * 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 9e7905759f2d..655c9b32c032 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -51,7 +51,7 @@ interface IAccessibilityManager { 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/Editor.java b/core/java/android/widget/Editor.java index 617d3dd67306..3a61fcda163b 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -2872,6 +2872,7 @@ public class Editor { protected PopupWindow mPopupWindow; protected ViewGroup mContentView; int mPositionX, mPositionY; + int mClippingLimitLeft, mClippingLimitRight; protected abstract void createPopupWindow(); protected abstract void initContentView(); @@ -2939,8 +2940,9 @@ public class Editor { // 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 @@ public class Editor { 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 @@ public class Editor { 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 @@ public class Editor { 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 @@ public class Editor { } }); - 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 @@ public class Editor { 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 @@ public class Editor { @Override protected int getVerticalLocalPosition(int line) { - return mTextView.getLayout().getLineBottom(line); + return mTextView.getLayout().getLineBottom(line) - mContainerMarginTop; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/chooser/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index a8bc36e58e19..27333915b2b6 100644 --- a/packages/SystemUI/src/com/android/systemui/chooser/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.chooser; +package com.android.internal.app; import android.animation.ObjectAnimator; import android.annotation.NonNull; @@ -25,7 +25,6 @@ import android.content.Intent; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.content.ServiceConnection; -import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.LabeledIntent; import android.content.pm.PackageManager; @@ -36,7 +35,6 @@ import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -67,12 +65,9 @@ import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.ListView; import com.android.internal.R; -import com.android.internal.app.IntentForwarderActivity; -import com.android.internal.app.ResolverActivity; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -96,11 +91,6 @@ public class ChooserActivity extends ResolverActivity { private ChooserListAdapter mChooserListAdapter; private ChooserRowAdapter mChooserRowAdapter; - private SharedPreferences mPinnedSharedPrefs; - private static final float PINNED_TARGET_SCORE_BOOST = 1000.f; - private static final String PINNED_SHARED_PREFS_NAME = "chooser_pin_settings"; - private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment"; - private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>(); private static final int CHOOSER_TARGET_SERVICE_RESULT = 1; @@ -217,18 +207,12 @@ public class ChooserActivity extends ResolverActivity { mRefinementIntentSender = intent.getParcelableExtra( Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER); setSafeForwardingMode(true); - - mPinnedSharedPrefs = getPinnedSharedPrefs(this); super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents, null, false); MetricsLogger.action(this, MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN); } - static SharedPreferences getPinnedSharedPrefs(Context context) { - return context.getSharedPreferences(PINNED_SHARED_PREFS_NAME, MODE_PRIVATE); - } - @Override protected void onDestroy() { super.onDestroy(); @@ -259,7 +243,7 @@ public class ChooserActivity extends ResolverActivity { } @Override - public void onActivityStarted(TargetInfo cti) { + void onActivityStarted(TargetInfo cti) { if (mChosenComponentSender != null) { final ComponentName target = cti.getResolvedComponentName(); if (target != null) { @@ -275,7 +259,7 @@ public class ChooserActivity extends ResolverActivity { } @Override - public void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter, + void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter, boolean alwaysUseOption) { final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null; mChooserListAdapter = (ChooserListAdapter) adapter; @@ -288,17 +272,17 @@ public class ChooserActivity extends ResolverActivity { } @Override - public int getLayoutResource() { + int getLayoutResource() { return R.layout.chooser_grid; } @Override - public boolean shouldGetActivityMetadata() { + boolean shouldGetActivityMetadata() { return true; } @Override - public boolean shouldAutoLaunchSingleChoice(TargetInfo target) { + boolean shouldAutoLaunchSingleChoice(TargetInfo target) { final Intent intent = target.getResolvedIntent(); final ResolveInfo resolve = target.getResolveInfo(); @@ -315,16 +299,6 @@ public class ChooserActivity extends ResolverActivity { return false; } - @Override - public void showTargetDetails(ResolveInfo ri) { - ComponentName name = ri.activityInfo.getComponentName(); - boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false); - ResolverTargetActionsDialogFragment f = - new ResolverTargetActionsDialogFragment(ri.loadLabel(getPackageManager()), - name, pinned); - f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); - } - private void modifyTargetIntent(Intent in) { final String action = in.getAction(); if (Intent.ACTION_SEND.equals(action) || @@ -366,7 +340,7 @@ public class ChooserActivity extends ResolverActivity { } @Override - public void startSelected(int which, boolean always, boolean filtered) { + void startSelected(int which, boolean always, boolean filtered) { super.startSelected(which, always, filtered); if (mChooserListAdapter != null) { @@ -497,7 +471,7 @@ public class ChooserActivity extends ResolverActivity { mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT); } - public void onSetupVoiceInteraction() { + void onSetupVoiceInteraction() { // Do nothing. We'll send the voice stuff ourselves. } @@ -569,7 +543,7 @@ public class ChooserActivity extends ResolverActivity { } @Override - public ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents, + ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) { final ChooserListAdapter adapter = new ChooserListAdapter(context, payloadIntents, @@ -737,11 +711,6 @@ public class ChooserActivity extends ResolverActivity { } return results; } - - @Override - public boolean isPinned() { - return mSourceInfo != null ? mSourceInfo.isPinned() : false; - } } public class ChooserListAdapter extends ResolveListAdapter { @@ -808,20 +777,6 @@ public class ChooserActivity extends ResolverActivity { } @Override - public boolean isComponentPinned(ComponentName name) { - return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false); - } - - @Override - public float getScore(DisplayResolveInfo target) { - float score = super.getScore(target); - if (target.isPinned()) { - score += PINNED_TARGET_SCORE_BOOST; - } - return score; - } - - @Override public View onCreateView(ViewGroup parent) { return mInflater.inflate( com.android.internal.R.layout.resolve_grid_item, parent, false); @@ -1166,7 +1121,7 @@ public class ChooserActivity extends ResolverActivity { v.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { - showTargetDetails( + showAppDetails( mChooserListAdapter.resolveInfoForPosition( holder.itemIndices[column], true)); return true; diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 12449871bad9..dbec7405fe49 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -100,7 +100,7 @@ public class IntentForwarderActivity extends Activity { final boolean shouldShowDisclosure = ri == null || ri.activityInfo == null || !"android".equals(ri.activityInfo.packageName) || !(ResolverActivity.class.getName().equals(ri.activityInfo.name) - || "com.android.systemui.chooser.ChooserActivity".equals(ri.activityInfo.name)); + || ChooserActivity.class.getName().equals(ri.activityInfo.name)); try { startActivityAsCaller(newIntent, null, false, targetUserId); diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java index 71c2c21df48b..c7459d7b274c 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 @@ public class LocaleHelper { * @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/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 7eb8708cb916..ec148c554bb7 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -22,7 +22,6 @@ import android.app.ActivityThread; import android.app.VoiceInteractor.PickOptionRequest; import android.app.VoiceInteractor.PickOptionRequest.Option; import android.app.VoiceInteractor.Prompt; -import android.content.pm.ComponentInfo; import android.os.AsyncTask; import android.provider.Settings; import android.text.TextUtils; @@ -337,12 +336,12 @@ public class ResolverActivity extends Activity { /** * Perform any initialization needed for voice interaction. */ - public void onSetupVoiceInteraction() { + void onSetupVoiceInteraction() { // Do it right now. Subclasses may delay this and send it later. sendVoiceChoicesIfNeeded(); } - public void sendVoiceChoicesIfNeeded() { + void sendVoiceChoicesIfNeeded() { if (!isVoiceInteraction()) { // Clearly not needed. return; @@ -383,7 +382,7 @@ public class ResolverActivity extends Activity { return null; } - public int getLayoutResource() { + int getLayoutResource() { return R.layout.resolver_list; } @@ -592,7 +591,7 @@ public class ResolverActivity extends Activity { mAlwaysUseOption); } - public void startSelected(int which, boolean always, boolean filtered) { + void startSelected(int which, boolean always, boolean filtered) { if (isFinishing()) { return; } @@ -762,7 +761,7 @@ public class ResolverActivity extends Activity { return true; } - public void safelyStartActivity(TargetInfo cti) { + void safelyStartActivity(TargetInfo cti) { // If needed, show that intent is forwarded // from managed profile to owner or other way around. if (mProfileSwitchMessageId != -1) { @@ -792,26 +791,26 @@ public class ResolverActivity extends Activity { } } - public void onActivityStarted(TargetInfo cti) { + void onActivityStarted(TargetInfo cti) { // Do nothing } - public boolean shouldGetActivityMetadata() { + boolean shouldGetActivityMetadata() { return false; } - public boolean shouldAutoLaunchSingleChoice(TargetInfo target) { + boolean shouldAutoLaunchSingleChoice(TargetInfo target) { return true; } - public void showTargetDetails(ResolveInfo ri) { + void showAppDetails(ResolveInfo ri) { Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) .setData(Uri.fromParts("package", ri.activityInfo.packageName, null)) .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); startActivity(in); } - public ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents, + ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) { return new ResolveListAdapter(context, payloadIntents, initialIntents, rList, @@ -821,7 +820,7 @@ public class ResolverActivity extends Activity { /** * Returns true if the activity is finishing and creation should halt */ - public boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents, + boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, boolean alwaysUseOption) { // The last argument of createAdapter is whether to do special handling // of the last used choice to highlight it in the list. We need to always @@ -868,7 +867,7 @@ public class ResolverActivity extends Activity { return false; } - public void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter, + void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter, boolean alwaysUseOption) { final boolean useHeader = adapter.hasFilteredItem(); final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null; @@ -899,7 +898,7 @@ public class ResolverActivity extends Activity { && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName); } - public final class DisplayResolveInfo implements TargetInfo { + final class DisplayResolveInfo implements TargetInfo { private final ResolveInfo mResolveInfo; private final CharSequence mDisplayLabel; private Drawable mDisplayIcon; @@ -907,9 +906,8 @@ public class ResolverActivity extends Activity { private final CharSequence mExtendedInfo; private final Intent mResolvedIntent; private final List<Intent> mSourceIntents = new ArrayList<>(); - private boolean mPinned; - public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel, + DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel, CharSequence pInfo, Intent pOrigIntent) { mSourceIntents.add(originalIntent); mResolveInfo = pri; @@ -934,7 +932,6 @@ public class ResolverActivity extends Activity { mExtendedInfo = other.mExtendedInfo; mResolvedIntent = new Intent(other.mResolvedIntent); mResolvedIntent.fillIn(fillInIntent, flags); - mPinned = other.mPinned; } public ResolveInfo getResolveInfo() { @@ -1029,15 +1026,6 @@ public class ResolverActivity extends Activity { activity.startActivityAsUser(mResolvedIntent, options, user); return false; } - - @Override - public boolean isPinned() { - return mPinned; - } - - public void setPinned(boolean pinned) { - mPinned = pinned; - } } /** @@ -1051,7 +1039,7 @@ public class ResolverActivity extends Activity { * * @return the resolved intent for this target */ - Intent getResolvedIntent(); + public Intent getResolvedIntent(); /** * Get the resolved component name that represents this target. Note that this may not @@ -1060,7 +1048,7 @@ public class ResolverActivity extends Activity { * * @return the resolved ComponentName for this target */ - ComponentName getResolvedComponentName(); + public ComponentName getResolvedComponentName(); /** * Start the activity referenced by this target. @@ -1069,7 +1057,7 @@ public class ResolverActivity extends Activity { * @param options ActivityOptions bundle * @return true if the start completed successfully */ - boolean start(Activity activity, Bundle options); + public boolean start(Activity activity, Bundle options); /** * Start the activity referenced by this target as if the ResolverActivity's caller @@ -1080,7 +1068,7 @@ public class ResolverActivity extends Activity { * @param userId userId to start as or {@link UserHandle#USER_NULL} for activity's caller * @return true if the start completed successfully */ - boolean startAsCaller(Activity activity, Bundle options, int userId); + public boolean startAsCaller(Activity activity, Bundle options, int userId); /** * Start the activity referenced by this target as a given user. @@ -1090,7 +1078,7 @@ public class ResolverActivity extends Activity { * @param user handle for the user to start the activity as * @return true if the start completed successfully */ - boolean startAsUser(Activity activity, Bundle options, UserHandle user); + public boolean startAsUser(Activity activity, Bundle options, UserHandle user); /** * Return the ResolveInfo about how and why this target matched the original query @@ -1098,14 +1086,14 @@ public class ResolverActivity extends Activity { * * @return ResolveInfo representing this target's match */ - ResolveInfo getResolveInfo(); + public ResolveInfo getResolveInfo(); /** * Return the human-readable text label for this target. * * @return user-visible target label */ - CharSequence getDisplayLabel(); + public CharSequence getDisplayLabel(); /** * Return any extended info for this target. This may be used to disambiguate @@ -1113,40 +1101,35 @@ public class ResolverActivity extends Activity { * * @return human-readable disambig string or null if none present */ - CharSequence getExtendedInfo(); + public CharSequence getExtendedInfo(); /** * @return The drawable that should be used to represent this target */ - Drawable getDisplayIcon(); + public Drawable getDisplayIcon(); /** * @return The (small) icon to badge the target with */ - Drawable getBadgeIcon(); + public Drawable getBadgeIcon(); /** * @return The content description for the badge icon */ - CharSequence getBadgeContentDescription(); + public CharSequence getBadgeContentDescription(); /** * Clone this target with the given fill-in information. */ - TargetInfo cloneFilledIn(Intent fillInIntent, int flags); + public TargetInfo cloneFilledIn(Intent fillInIntent, int flags); /** * @return the list of supported source intents deduped against this single target */ - List<Intent> getAllSourceIntents(); - - /** - * @return true if this target should be pinned to the front by the request of the user - */ - boolean isPinned(); + public List<Intent> getAllSourceIntents(); } - public class ResolveListAdapter extends BaseAdapter { + class ResolveListAdapter extends BaseAdapter { private final List<Intent> mIntents; private final Intent[] mInitialIntents; private final List<ResolveInfo> mBaseResolveList; @@ -1393,12 +1376,9 @@ public class ResolverActivity extends Activity { } } if (!found) { - final ComponentName name = new ComponentName( - newInfo.activityInfo.packageName, newInfo.activityInfo.name); - final ResolvedComponentInfo rci = new ResolvedComponentInfo(name, - intent, newInfo); - rci.setPinned(isComponentPinned(name)); - into.add(rci); + into.add(new ResolvedComponentInfo(new ComponentName( + newInfo.activityInfo.packageName, newInfo.activityInfo.name), + intent, newInfo)); } } } @@ -1474,8 +1454,6 @@ public class ResolverActivity extends Activity { final Intent replaceIntent = getReplacementIntent(add.activityInfo, intent); final DisplayResolveInfo dri = new DisplayResolveInfo(intent, add, roLabel, extraInfo, replaceIntent); - final ComponentInfo ci = add.getComponentInfo(); - dri.setPinned(rci.isPinned()); addResolveInfo(dri); if (replaceIntent == intent) { // Only add alternates if we didn't get a specific replacement from @@ -1559,11 +1537,11 @@ public class ResolverActivity extends Activity { return false; } - public int getDisplayResolveInfoCount() { + protected int getDisplayResolveInfoCount() { return mDisplayList.size(); } - public DisplayResolveInfo getDisplayResolveInfo(int index) { + protected DisplayResolveInfo getDisplayResolveInfo(int index) { // Used to query services. We only query services for primary targets, not alternates. return mDisplayList.get(index); } @@ -1593,10 +1571,6 @@ public class ResolverActivity extends Activity { return !TextUtils.isEmpty(info.getExtendedInfo()); } - public boolean isComponentPinned(ComponentName name) { - return false; - } - public final void bindView(int position, View view) { onBindView(view, getItem(position)); } @@ -1633,7 +1607,6 @@ public class ResolverActivity extends Activity { static final class ResolvedComponentInfo { public final ComponentName name; - private boolean mPinned; private final List<Intent> mIntents = new ArrayList<>(); private final List<ResolveInfo> mResolveInfos = new ArrayList<>(); @@ -1676,14 +1649,6 @@ public class ResolverActivity extends Activity { } return -1; } - - public boolean isPinned() { - return mPinned; - } - - public void setPinned(boolean pinned) { - mPinned = pinned; - } } static class ViewHolder { @@ -1737,7 +1702,7 @@ public class ResolverActivity extends Activity { return false; } ResolveInfo ri = mAdapter.resolveInfoForPosition(position, true); - showTargetDetails(ri); + showAppDetails(ri); return true; } diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java index 964a7f53e357..31556e29bc32 100644 --- a/core/java/com/android/internal/app/ResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -48,7 +48,7 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { private static final boolean DEBUG = false; // Two weeks - private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 7; + private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12; @@ -171,27 +171,15 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { } } - final boolean lPinned = lhsp.isPinned(); - final boolean rPinned = rhsp.isPinned(); + if (mStats != null) { + final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName( + lhs.activityInfo.packageName, lhs.activityInfo.name)); + final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName( + rhs.activityInfo.packageName, rhs.activityInfo.name)); + final float diff = rhsTarget.score - lhsTarget.score; - if (lPinned && !rPinned) { - return -1; - } else if (!lPinned && rPinned) { - return 1; - } - - // Pinned items stay stable within a normal lexical sort and ignore scoring. - if (!lPinned && !rPinned) { - if (mStats != null) { - final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName( - lhs.activityInfo.packageName, lhs.activityInfo.name)); - final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName( - rhs.activityInfo.packageName, rhs.activityInfo.name)); - final float diff = rhsTarget.score - lhsTarget.score; - - if (diff != 0) { - return diff > 0 ? 1 : -1; - } + if (diff != 0) { + return diff > 0 ? 1 : -1; } } diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 976ef4bb0243..480d8064fa7b 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -920,14 +920,14 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 3f468acead60..ba456f9ce052 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 @@ public class LockPatternUtils { 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 class LockPatternUtils { } 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 000000000000..b45fd06c8a71 --- /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 b977e377f2f3..d25da7823719 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -54,6 +54,10 @@ struct audio_attributes_fields_t { }; 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 void android_media_AudioRecord_disableDeviceCallback( } } +// ---------------------------------------------------------------------------- +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 @@ static const JNINativeMethod gMethods[] = { {"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 @@ int register_android_media_AudioRecord(JNIEnv *env) 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/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4ab81e990513..1c3db104dc3c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2887,6 +2887,19 @@ android:theme="@style/Theme.Material.DayNight.DarkActionBar" android:forceDeviceEncrypted="true" android:encryptionAware="true"> + <activity android:name="com.android.internal.app.ChooserActivity" + android:theme="@style/Theme.DeviceDefault.Resolver" + android:finishOnCloseSystemDialogs="true" + android:excludeFromRecents="true" + android:documentLaunchMode="never" + android:relinquishTaskIdentity="true" + android:process=":ui"> + <intent-filter> + <action android:name="android.intent.action.CHOOSER" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.VOICE" /> + </intent-filter> + </activity> <activity android:name="com.android.internal.app.IntentForwarderActivity" android:finishOnCloseSystemDialogs="true" android:theme="@style/Theme.NoDisplay" diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml index aaa2dbc389dc..46a2b2af1a28 100644 --- a/core/res/res/layout/app_error_dialog.xml +++ b/core/res/res/layout/app_error_dialog.xml @@ -26,7 +26,7 @@ > - <TextView + <Button android:id="@+id/aerr_restart" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -34,7 +34,7 @@ style="@style/aerr_list_item" /> - <TextView + <Button android:id="@+id/aerr_reset" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -42,7 +42,7 @@ style="@style/aerr_list_item" /> - <TextView + <Button android:id="@+id/aerr_report" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -50,7 +50,7 @@ style="@style/aerr_list_item" /> - <TextView + <Button android:id="@+id/aerr_close" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -58,7 +58,7 @@ style="@style/aerr_list_item" /> - <TextView + <Button android:id="@+id/aerr_mute" android:layout_width="match_parent" android:layout_height="wrap_content" 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 e8ff186248f6..aa78eff612c8 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 9fcd3569b7ef..aea9b44622c4 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 fe02d4ea417d..17e93d0a9eae 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 62e315b4e4f7..78268036c827 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 f92e7f02892c..7c6f3389c5d0 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 b2eab4c7498c..26421fb59ebb 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/styles.xml b/core/res/res/values/styles.xml index b660277847c4..f0960c78d418 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1398,7 +1398,7 @@ please see styles_device_defaults.xml. </style> <!-- @hide --> - <style name="aerr_list_item" parent="Widget.Material.Light.TextView"> + <style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless"> <item name="minHeight">?attr/listPreferredItemHeightSmall</item> <item name="textAppearance">?attr/textAppearanceListItemSmall</item> <item name="textColor">?attr/textColorAlertDialogListItem</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index aa44d7c9f521..74ca8a5a3ee4 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 4d4acb94c255..1cf15ac01154 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -201,7 +201,6 @@ void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float str 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 7c218936a1d1..800b91497058 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -826,6 +826,33 @@ public class AudioRecord implements AudioRouting } /** + * 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 @@ public class AudioRecord implements AudioRouting 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 965ba859dcbd..be8ca151580d 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 869512dd254c..93e6dacdd98c 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -473,8 +473,9 @@ public final class MediaBrowser { // 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 @@ public final class MediaBrowser { // 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 @@ public final class MediaBrowser { 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 @@ public final class MediaBrowser { * 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 @@ public final class MediaBrowser { } @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 b1a51a56db28..3d9b60deed2f 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -605,6 +605,7 @@ public final class MediaController { /** * 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 @@ public final class MediaController { * 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 @@ public final class MediaController { /** * 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 e1e9b792810f..8c5b19c36f11 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -87,6 +87,12 @@ public final class MediaSession { 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 @@ public final class MediaSession { @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 bbe04b5875eb..1079a1f9a107 100644 --- a/media/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java @@ -133,6 +133,21 @@ public final class PlaybackState implements Parcelable { 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 0febc162e5a7..d18933385463 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -41,6 +41,7 @@ import android.view.Surface; 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 3bf415ba4bc5..395c9f3b384e 100644 --- a/media/java/android/media/tv/ITvInputManagerCallback.aidl +++ b/media/java/android/media/tv/ITvInputManagerCallback.aidl @@ -29,5 +29,5 @@ oneway interface ITvInputManagerCallback { 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 9f13882685aa..74ab56215ff2 100644 --- a/media/java/android/media/tv/ITvInputServiceCallback.aidl +++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl @@ -27,6 +27,4 @@ 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); } diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 671a86f0d1ae..20491e4baa70 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -107,15 +107,6 @@ public final class TvInputInfo implements Parcelable { */ public static final String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID"; - private static final SparseIntArray sHardwareTypeToTvInputType = new SparseIntArray(); - - private static final String XML_START_TAG_NAME = "tv-input"; - private static final String DELIMITER_INFO_IN_ID = "/"; - private static final String PREFIX_HDMI_DEVICE = "HDMI"; - private static final String PREFIX_HARDWARE_DEVICE = "HW"; - private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4; - private static final int LENGTH_HDMI_DEVICE_ID = 2; - private final ResolveInfo mService; private final String mId; private final String mParentId; @@ -137,21 +128,6 @@ public final class TvInputInfo implements Parcelable { private Uri mIconUri; private boolean mIsConnectedToHdmiSwitch; - static { - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE, - TYPE_OTHER); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_TUNER, TYPE_TUNER); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPOSITE, TYPE_COMPOSITE); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SVIDEO, TYPE_SVIDEO); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SCART, TYPE_SCART); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPONENT, TYPE_COMPONENT); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_VGA, TYPE_VGA); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DVI, TYPE_DVI); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI, TYPE_HDMI); - sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DISPLAY_PORT, - TYPE_DISPLAY_PORT); - } - /** * Create a new instance of the TvInputInfo class, instantiating it from the given Context, * ResolveInfo, and HdmiDeviceInfo. @@ -260,93 +236,6 @@ public final class TvInputInfo implements Parcelable { .build(); } - static TvInputInfo createTvInputInfo(Context context, ResolveInfo resolveInfo, Icon icon, - int labelResId, int tunerCount, boolean canRecord, HdmiDeviceInfo hdmiDeviceInfo, - String parentId, TvInputHardwareInfo tvInputHardwareInfo) - throws IOException, XmlPullParserException { - ComponentName componentName = new ComponentName(resolveInfo.serviceInfo.packageName, - resolveInfo.serviceInfo.name); - String id; - int type; - boolean isHardwareInput = false; - boolean isConnectedToHdmiSwitch = false; - - if (hdmiDeviceInfo != null) { - id = generateInputIdForHdmiDevice(componentName, hdmiDeviceInfo); - type = TYPE_HDMI; - isHardwareInput = true; - isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0; - tunerCount = 0; - } else if (tvInputHardwareInfo != null) { - id = generateInputIdForHardware(componentName, tvInputHardwareInfo); - type = sHardwareTypeToTvInputType.get(tvInputHardwareInfo.getType(), TYPE_TUNER); - isHardwareInput = true; - tunerCount = 0; - } else { - id = generateInputIdForComponentName(componentName); - type = TYPE_TUNER; - } - - TvInputInfo info = new TvInputInfo(resolveInfo, id, parentId, type, isHardwareInput, - isConnectedToHdmiSwitch, tunerCount, canRecord); - return parseServiceMetadata(context, resolveInfo, type, info); - } - - private static TvInputInfo parseServiceMetadata( - Context context, ResolveInfo service, int inputType, TvInputInfo input) - throws XmlPullParserException, IOException { - ServiceInfo si = service.serviceInfo; - PackageManager pm = context.getPackageManager(); - XmlResourceParser parser = null; - try { - parser = si.loadXmlMetaData(pm, TvInputService.SERVICE_META_DATA); - if (parser == null) { - throw new XmlPullParserException("No " + TvInputService.SERVICE_META_DATA - + " meta-data for " + si.name); - } - - Resources res = pm.getResourcesForApplication(si.applicationInfo); - AttributeSet attrs = Xml.asAttributeSet(parser); - - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && type != XmlPullParser.START_TAG) { - } - - String nodeName = parser.getName(); - if (!XML_START_TAG_NAME.equals(nodeName)) { - throw new XmlPullParserException( - "Meta-data does not start with tv-input-service tag in " + si.name); - } - - TypedArray sa = res.obtainAttributes(attrs, - com.android.internal.R.styleable.TvInputService); - input.mSetupActivity = sa.getString( - com.android.internal.R.styleable.TvInputService_setupActivity); - if (DEBUG) { - Log.d(TAG, "Setup activity loaded. [" + input.mSetupActivity + "] for " + si.name); - } - if (inputType == TYPE_TUNER && TextUtils.isEmpty(input.mSetupActivity)) { - throw new XmlPullParserException("Setup activity not found in " + si.name); - } - input.mSettingsActivity = sa.getString( - com.android.internal.R.styleable.TvInputService_settingsActivity); - if (DEBUG) { - Log.d(TAG, "Settings activity loaded. [" + input.mSettingsActivity + "] for " - + si.name); - } - sa.recycle(); - - } catch (NameNotFoundException e) { - throw new XmlPullParserException("Unable to create context for: " + si.packageName); - } finally { - if (parser != null) { - parser.close(); - } - } - return input; - } - /** * Constructor. * @@ -645,46 +534,6 @@ public final class TvInputInfo implements Parcelable { return mService.serviceInfo.loadIcon(context.getPackageManager()); } - /** - * Used to generate an input id from a ComponentName. - * - * @param name the component name for generating an input id. - * @return the generated input id for the given {@code name}. - */ - private static String generateInputIdForComponentName(ComponentName name) { - return name.flattenToShortString(); - } - - /** - * Used to generate an input id from a ComponentName and HdmiDeviceInfo. - * - * @param name the component name for generating an input id. - * @param deviceInfo HdmiDeviceInfo describing this TV input. - * @return the generated input id for the given {@code name} and {@code deviceInfo}. - */ - private static String generateInputIdForHdmiDevice( - ComponentName name, HdmiDeviceInfo deviceInfo) { - // Example of the format : "/HDMI%04X%02X" - String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE - + "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X" - + "%0" + LENGTH_HDMI_DEVICE_ID + "X"; - return name.flattenToShortString() + String.format(Locale.ENGLISH, format, - deviceInfo.getPhysicalAddress(), deviceInfo.getId()); - } - - /** - * Used to generate an input id from a ComponentName and TvInputHardwareInfo - * - * @param name the component name for generating an input id. - * @param hardwareInfo TvInputHardwareInfo describing this TV input. - * @return the generated input id for the given {@code name} and {@code hardwareInfo}. - */ - private static String generateInputIdForHardware( - ComponentName name, TvInputHardwareInfo hardwareInfo) { - return name.flattenToShortString() + DELIMITER_INFO_IN_ID + PREFIX_HARDWARE_DEVICE - + hardwareInfo.getDeviceId(); - } - public static final Parcelable.Creator<TvInputInfo> CREATOR = new Parcelable.Creator<TvInputInfo>() { @Override @@ -720,6 +569,32 @@ public final class TvInputInfo implements Parcelable { * A convenience builder for creating {@link TvInputInfo} objects. */ public static final class Builder { + private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4; + private static final int LENGTH_HDMI_DEVICE_ID = 2; + + private static final String XML_START_TAG_NAME = "tv-input"; + private static final String DELIMITER_INFO_IN_ID = "/"; + private static final String PREFIX_HDMI_DEVICE = "HDMI"; + private static final String PREFIX_HARDWARE_DEVICE = "HW"; + + private static final SparseIntArray sHardwareTypeToTvInputType = new SparseIntArray(); + static { + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE, + TYPE_OTHER); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_TUNER, TYPE_TUNER); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPOSITE, + TYPE_COMPOSITE); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SVIDEO, TYPE_SVIDEO); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SCART, TYPE_SCART); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPONENT, + TYPE_COMPONENT); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_VGA, TYPE_VGA); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DVI, TYPE_DVI); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI, TYPE_HDMI); + sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DISPLAY_PORT, + TYPE_DISPLAY_PORT); + } + private final Context mContext; private final ResolveInfo mResolveInfo; private Icon mIcon; @@ -864,11 +739,102 @@ public final class TvInputInfo implements Parcelable { * @return TvInputInfo containing information about this TV input. * @throws IOException If there was an I/O error. * @throws XmlPullParserException If there was an XML parsing error. - * */ public TvInputInfo build() throws IOException, XmlPullParserException { - return createTvInputInfo(mContext, mResolveInfo, mIcon, mLabelResId, mTunerCount, - mCanRecord, mHdmiDeviceInfo, mParentId, mTvInputHardwareInfo); + ComponentName componentName = new ComponentName(mResolveInfo.serviceInfo.packageName, + mResolveInfo.serviceInfo.name); + String id; + int type; + boolean isHardwareInput = false; + boolean isConnectedToHdmiSwitch = false; + + if (mHdmiDeviceInfo != null) { + id = generateInputId(componentName, mHdmiDeviceInfo); + type = TYPE_HDMI; + isHardwareInput = true; + isConnectedToHdmiSwitch = (mHdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0; + mTunerCount = 0; + } else if (mTvInputHardwareInfo != null) { + id = generateInputId(componentName, mTvInputHardwareInfo); + type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER); + isHardwareInput = true; + mTunerCount = 0; + } else { + id = generateInputId(componentName); + type = TYPE_TUNER; + } + + TvInputInfo info = new TvInputInfo(mResolveInfo, id, mParentId, type, isHardwareInput, + isConnectedToHdmiSwitch, mTunerCount, mCanRecord); + return parseServiceMetadata(type, info); + } + + private static String generateInputId(ComponentName name) { + return name.flattenToShortString(); + } + + private static String generateInputId(ComponentName name, HdmiDeviceInfo hdmiDeviceInfo) { + // Example of the format : "/HDMI%04X%02X" + String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE + + "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X" + + "%0" + LENGTH_HDMI_DEVICE_ID + "X"; + return name.flattenToShortString() + String.format(Locale.ENGLISH, format, + hdmiDeviceInfo.getPhysicalAddress(), hdmiDeviceInfo.getId()); + } + + private static String generateInputId(ComponentName name, + TvInputHardwareInfo tvInputHardwareInfo) { + return name.flattenToShortString() + DELIMITER_INFO_IN_ID + PREFIX_HARDWARE_DEVICE + + tvInputHardwareInfo.getDeviceId(); + } + + private TvInputInfo parseServiceMetadata(int inputType, TvInputInfo info) + throws XmlPullParserException, IOException { + ServiceInfo si = mResolveInfo.serviceInfo; + PackageManager pm = mContext.getPackageManager(); + try (XmlResourceParser parser = + si.loadXmlMetaData(pm, TvInputService.SERVICE_META_DATA)) { + if (parser == null) { + throw new XmlPullParserException("No " + TvInputService.SERVICE_META_DATA + + " meta-data for " + si.name); + } + + Resources res = pm.getResourcesForApplication(si.applicationInfo); + AttributeSet attrs = Xml.asAttributeSet(parser); + + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + + String nodeName = parser.getName(); + if (!XML_START_TAG_NAME.equals(nodeName)) { + throw new XmlPullParserException( + "Meta-data does not start with tv-input-service tag in " + si.name); + } + + TypedArray sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.TvInputService); + info.mSetupActivity = sa.getString( + com.android.internal.R.styleable.TvInputService_setupActivity); + if (DEBUG) { + Log.d(TAG, "Setup activity loaded. [" + info.mSetupActivity + "] for " + + si.name); + } + if (inputType == TYPE_TUNER && TextUtils.isEmpty(info.mSetupActivity)) { + throw new XmlPullParserException("Setup activity not found in " + si.name); + } + info.mSettingsActivity = sa.getString( + com.android.internal.R.styleable.TvInputService_settingsActivity); + if (DEBUG) { + Log.d(TAG, "Settings activity loaded. [" + info.mSettingsActivity + "] for " + + si.name); + } + sa.recycle(); + } catch (NameNotFoundException e) { + throw new XmlPullParserException("Unable to create context for: " + si.packageName); + } + return info; } } diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index f1de8fdc1817..86bded946ef2 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -726,12 +726,11 @@ public final class TvInputManager { } /** - * This is called when the information about a given TV input is changed. + * This is called when the information about a given TV input has been changed. * - * @param inputId The ID of the TV input. * @param inputInfo TvInputInfo object that contains the information about the TV input. */ - public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) { + public void onTvInputInfoChanged(TvInputInfo inputInfo) { } } @@ -784,11 +783,11 @@ public final class TvInputManager { }); } - public void postTvInputInfoChanged(final String inputId, final TvInputInfo inputInfo) { + public void postTvInputInfoChanged(final TvInputInfo inputInfo) { mHandler.post(new Runnable() { @Override public void run() { - mCallback.onTvInputInfoChanged(inputId, inputInfo); + mCallback.onTvInputInfoChanged(inputInfo); } }); } @@ -1089,10 +1088,10 @@ public final class TvInputManager { } @Override - public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) { + public void onTvInputInfoChanged(TvInputInfo inputInfo) { synchronized (mLock) { for (TvInputCallbackRecord record : mCallbackRecords) { - record.postTvInputInfoChanged(inputId, inputInfo); + record.postTvInputInfoChanged(inputInfo); } } } @@ -1143,6 +1142,23 @@ public final class TvInputManager { } /** + * 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 f74ae660669a..77e81dc9a76e 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -262,16 +262,16 @@ public abstract class TvInputService extends Service { * <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 abstract class TvInputService extends Service { 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 @@ -1938,7 +1938,6 @@ public abstract class TvInputService extends Service { private static final int DO_REMOVE_HARDWARE_TV_INPUT = 5; private static final int DO_ADD_HDMI_TV_INPUT = 6; private static final int DO_REMOVE_HDMI_TV_INPUT = 7; - private static final int DO_SET_TV_INPUT_INFO = 8; private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) { int n = mCallbacks.beginBroadcast(); @@ -1976,18 +1975,6 @@ public abstract class TvInputService extends Service { mCallbacks.finishBroadcast(); } - private void broadcastSetTvInputInfo(String inputId, TvInputInfo inputInfo) { - int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; ++i) { - try { - mCallbacks.getBroadcastItem(i).setTvInputInfo(inputId, inputInfo); - } catch (RemoteException e) { - Log.e(TAG, "error in broadcastSetTvInputInfo", e); - } - } - mCallbacks.finishBroadcast(); - } - @Override public final void handleMessage(Message msg) { switch (msg.what) { @@ -2120,16 +2107,6 @@ public abstract class TvInputService extends Service { } 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/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl index fe7ebfa95423..6ca5ac59369f 100644 --- a/media/java/android/service/media/IMediaBrowserService.aidl +++ b/media/java/android/service/media/IMediaBrowserService.aidl @@ -16,7 +16,7 @@ import android.os.ResultReceiver; 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 dadb025060b7..e6b0e8cfbb13 100644 --- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl +++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl @@ -13,6 +13,10 @@ import android.os.Bundle; * @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 @@ oneway interface IMediaBrowserServiceCallbacks { */ 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 6cf90d594dce..299b77071c55 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -589,7 +589,14 @@ public abstract class MediaBrowserService extends Service { 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 025133f3ff00..3b892cb3e4ab 100644 --- a/media/jni/android_media_MediaDataSource.cpp +++ b/media/jni/android_media_MediaDataSource.cpp @@ -150,4 +150,8 @@ void JMediaDataSource::close() { 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 2bc237e02b06..34624ebbda05 100644 --- a/media/jni/android_media_MediaDataSource.h +++ b/media/jni/android_media_MediaDataSource.h @@ -45,6 +45,7 @@ public: 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 c3452d585a6e..fa9ff0153c87 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 ff28e158238a..e8d8c8ebfda1 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 5ffc435a581b..93096930d220 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -104,7 +104,6 @@ public abstract class BaseActivity extends Activity implements SearchManagerList 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 393fdcd0586a..f51f689c67be 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.BaseAdapter; 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 @@ public class FilesActivity extends BaseActivity { pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); - newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - newWindow.setVisible(mProductivityDevice); - Menus.disableHiddenItems(menu, pasteFromCb); return true; } @@ -287,6 +284,14 @@ public class FilesActivity extends BaseActivity { 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 b3d0cf37bbd5..7930c28fc6c2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java @@ -74,6 +74,9 @@ public class LauncherActivity extends Activity { 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 @@ public class LauncherActivity extends Activity { 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 112914e93830..959fac69c817 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java @@ -165,22 +165,27 @@ class MtpDatabase { 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 (availableIndex != -1) { - availableBytes += cursor.getLong(availableIndex); + 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); + } } + 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 97ea717a4c15..80759994e6a1 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 @@ public class MtpDatabaseTest extends AndroidTestCase { 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 d3c1364adac8..210682f9cd80 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.app.admin.DevicePolicyManager; 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; @@ -178,7 +179,7 @@ public class RestrictedLockUtils { if (userInfo.isManagedProfile()) { // If userInfo.id is a managed profile, we also need to look at // the policies set on the parent. - DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin); + DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo); if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id) & keyguardFeatures) != 0) { if (enforcedAdmin == null) { @@ -227,6 +228,26 @@ public class RestrictedLockUtils { } /** + * 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. @@ -375,7 +396,7 @@ public class RestrictedLockUtils { if (userInfo.isManagedProfile()) { // If userInfo.id is a managed profile, we also need to look at // the policies set on the parent. - DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin); + DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo); if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) { if (enforcedAdmin == null) { enforcedAdmin = new EnforcedAdmin(admin, userInfo.id); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 2ee4b122e73a..5b8ed28e6997 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -37,6 +37,7 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.support.annotation.NonNull; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -104,7 +105,8 @@ public class AccessPoint implements Comparable<AccessPoint> { private static final int PSK_WPA2 = 2; private static final int PSK_WPA_WPA2 = 3; - private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000; + public static final int SIGNAL_LEVELS = 4; + private final Context mContext; private String ssid; @@ -167,7 +169,7 @@ public class AccessPoint implements Comparable<AccessPoint> { } @Override - public int compareTo(AccessPoint other) { + public int compareTo(@NonNull AccessPoint other) { // Active one goes first. if (isActive() && !other.isActive()) return -1; if (!isActive() && other.isActive()) return 1; @@ -182,8 +184,9 @@ public class AccessPoint implements Comparable<AccessPoint> { if (networkId == WifiConfiguration.INVALID_NETWORK_ID && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1; - // Sort by signal strength. - int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi); + // Sort by signal strength, bucketed by level + int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS) + - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS); if (difference != 0) { return difference; } @@ -260,7 +263,7 @@ public class AccessPoint implements Comparable<AccessPoint> { if (mRssi == Integer.MAX_VALUE) { return -1; } - return WifiManager.calculateSignalLevel(mRssi, 4); + return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS); } public int getRssi() { diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk index e4d0fec843f1..88313bb50378 100644 --- a/packages/SystemUI/Android.mk +++ b/packages/SystemUI/Android.mk @@ -12,6 +12,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ 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 @@ LOCAL_RESOURCE_DIR := \ 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 52b7b7dfc128..2713fb51991c 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -155,10 +155,6 @@ <!-- TV picture-in-picture --> <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" /> - <!-- ChooserActivity --> - <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> - <uses-permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE" /> - <application android:name=".SystemUIApplication" android:persistent="true" @@ -240,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" @@ -442,20 +452,5 @@ <action android:name="com.android.systemui.action.CLEAR_TUNER" /> </intent-filter> </receiver> - - <activity android:name=".chooser.ChooserActivity" - android:theme="@*android:style/Theme.DeviceDefault.Resolver" - android:finishOnCloseSystemDialogs="true" - android:excludeFromRecents="true" - android:documentLaunchMode="never" - android:relinquishTaskIdentity="true" - android:process=":chooser"> - <intent-filter> - <action android:name="android.intent.action.CHOOSER" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.VOICE" /> - </intent-filter> - </activity> - </application> </manifest> 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 000000000000..5a6553ff90db --- /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 000000000000..80a478a6d3d8 --- /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 000000000000..fa07eb1b105c --- /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 000000000000..5002c1298eb2 --- /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 460433ea1c21..77b12641c8c6 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 000000000000..802acfed73e8 --- /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 000000000000..b4543bdeb57f --- /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 000000000000..fa1daadd2cee --- /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/arrays.xml b/packages/SystemUI/res/values/arrays.xml index 32025e06e5b9..bf0cba22ab0c 100644 --- a/packages/SystemUI/res/values/arrays.xml +++ b/packages/SystemUI/res/values/arrays.xml @@ -51,16 +51,4 @@ <item>0</item><item>3</item> <item>3</item><item>3</item> </array> - - <!-- Used in ResolverTargetActionsDialogFragment --> - <string-array name="resolver_target_actions_pin"> - <item>@string/pin_target</item> - <item>@string/app_info</item> - </string-array> - - <string-array name="resolver_target_actions_unpin"> - <item>@string/unpin_target</item> - <item>@string/app_info</item> - </string-array> - </resources> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 955efb501cc8..19bc75594db8 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 f0d9949fa90c..9bb6dc6abb75 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 000000000000..6f4c983586a4 --- /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/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 8b0350ab40ea..32d09e81b870 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 000000000000..77605bd3133e --- /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 000000000000..bfd8f8beb958 --- /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/strings.xml b/packages/SystemUI/res/values/strings.xml index 78242910f280..32da3c62e1f4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1343,11 +1343,6 @@ <!-- Accessibility description for data saver being off [CHAR LIMIT=NONE] --> <string name="accessibility_data_saver_off">Data Saver is off</string> - <!-- Resolver target actions strings --> - <string name="pin_target">Pin</string> - <string name="unpin_target">Unpin</string> - <string name="app_info">App info</string> - <!-- Label for feature switch [CHAR LIMIT=30] --> <string name="switch_bar_on">On</string> diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml new file mode 100644 index 000000000000..45cdc07c65ae --- /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/chooser/ResolverTargetActionsDialogFragment.java b/packages/SystemUI/src/com/android/systemui/chooser/ResolverTargetActionsDialogFragment.java deleted file mode 100644 index 839aa4556450..000000000000 --- a/packages/SystemUI/src/com/android/systemui/chooser/ResolverTargetActionsDialogFragment.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.chooser; - -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.ComponentName; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Settings; - -import com.android.systemui.R; - -/** - * Shows a dialog with actions to take on a chooser target - */ -public class ResolverTargetActionsDialogFragment extends DialogFragment - implements DialogInterface.OnClickListener { - private static final String NAME_KEY = "componentName"; - private static final String PINNED_KEY = "pinned"; - private static final String TITLE_KEY = "title"; - - // Sync with R.array.resolver_target_actions_* resources - private static final int TOGGLE_PIN_INDEX = 0; - private static final int APP_INFO_INDEX = 1; - - public ResolverTargetActionsDialogFragment() { - } - - public ResolverTargetActionsDialogFragment(CharSequence title, ComponentName name, - boolean pinned) { - Bundle args = new Bundle(); - args.putCharSequence(TITLE_KEY, title); - args.putParcelable(NAME_KEY, name); - args.putBoolean(PINNED_KEY, pinned); - setArguments(args); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - final int itemRes = args.getBoolean(PINNED_KEY, false) - ? R.array.resolver_target_actions_unpin - : R.array.resolver_target_actions_pin; - return new Builder(getContext()) - .setCancelable(true) - .setItems(itemRes, this) - .setTitle(args.getCharSequence(TITLE_KEY)) - .create(); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - final Bundle args = getArguments(); - ComponentName name = args.getParcelable(NAME_KEY); - switch (which) { - case TOGGLE_PIN_INDEX: - SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext()); - final String key = name.flattenToString(); - boolean currentVal = sp.getBoolean(name.flattenToString(), false); - if (currentVal) { - sp.edit().remove(key).apply(); - } else { - sp.edit().putBoolean(key, true).apply(); - } - - // Force the chooser to requery and resort things - getActivity().recreate(); - break; - case APP_INFO_INDEX: - Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.fromParts("package", name.getPackageName(), null)) - .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); - startActivity(in); - break; - } - dismiss(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java index 27d4c0ecf132..c7e5ea49b19f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java @@ -35,6 +35,10 @@ import java.util.ArrayList; 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 +105,9 @@ public class HumanInteractionClassifier extends Classifier { } 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/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 789e72e8f276..35000d3c3f11 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.graphics.drawable.Drawable; 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 @@ public abstract class QSTile<TState extends State> implements Listenable { 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/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 6a07a07a7033..dbb7423f6e56 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 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { @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/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index db8604759439..2f37943196fa 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 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { 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 724659c6a168..8328897c47b9 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 @@ public class LocationTile extends QSTile<QSTile.BooleanState> { // 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/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index b78fd2282441..d1301cf9592a 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 @@ package com.android.systemui.recents; 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; @@ -87,7 +89,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener 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 +215,14 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener 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 +919,11 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener 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/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 2882cecc6062..aa006d16aff0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -81,6 +81,7 @@ import java.util.Random; 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 +267,9 @@ public class SystemServicesProxy { 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 +358,13 @@ public class SystemServicesProxy { } /** + * 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 +977,20 @@ public class SystemServicesProxy { 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/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java new file mode 100644 index 000000000000..6593169a9523 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java @@ -0,0 +1,451 @@ +/* + * 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.*; +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 000000000000..8212c73e83f8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java @@ -0,0 +1,143 @@ +/* + * 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 000000000000..c4d5b2baa56f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java @@ -0,0 +1,252 @@ +/* + * 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.internal.logging.MetricsLogger; +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; + +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; + +/** + * 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 000000000000..b36a2281e1b4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java @@ -0,0 +1,69 @@ +/* + * 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.tv.animations.ViewFocusAnimator; +import com.android.systemui.recents.model.Task; + +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 000000000000..b505d65c2471 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java @@ -0,0 +1,157 @@ +/* + * 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.support.v17.leanback.widget.HorizontalGridView; +import android.util.AttributeSet; +import android.content.Context; +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 000000000000..0ee7b49e9980 --- /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.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 android.support.v7.widget.RecyclerView; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; + +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/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 67bb58ae8fc9..24ab5063d94e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -97,7 +97,8 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true); + ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false, + false); } catch (RemoteException e) { Log.w(TAG, "Failed to resize stack: " + e); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 240d32ec95bb..4edb976b0c4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -1175,7 +1175,7 @@ public abstract class BaseStatusBar extends SystemUI implements } protected void toggleKeyboardShortcuts() { - getKeyboardShortcuts().toggleKeyboardShortcuts(mContext); + getKeyboardShortcuts().toggleKeyboardShortcuts(); } protected void cancelPreloadingRecents() { @@ -1518,7 +1518,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected KeyboardShortcuts getKeyboardShortcuts() { if (mKeyboardShortcuts == null) { - mKeyboardShortcuts = new KeyboardShortcuts(); + mKeyboardShortcuts = new KeyboardShortcuts(mContext); } return mKeyboardShortcuts; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index b36fb7e65f7e..25e9a7aa1d8b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -19,25 +19,38 @@ package com.android.systemui.statusbar; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.graphics.Color; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Handler; +import android.os.Looper; +import android.util.DisplayMetrics; import android.util.Log; +import android.util.TypedValue; import android.view.KeyEvent; import android.view.KeyboardShortcutGroup; import android.view.KeyboardShortcutInfo; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.Window; -import android.view.WindowManager; import android.view.WindowManager.KeyboardShortcutsReceiver; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.recents.Recents; +import java.util.ArrayList; import java.util.List; import static android.content.Context.LAYOUT_INFLATER_SERVICE; -import static android.graphics.Color.TRANSPARENT; +import static android.graphics.Color.WHITE; import static android.view.Gravity.TOP; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; @@ -45,33 +58,44 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; * 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,45 +103,106 @@ public class KeyboardShortcuts { } } - 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 dismissKeyboardShortcutsDialog() { + if (mKeyboardShortcutsDialog != null) { + mKeyboardShortcutsDialog.dismiss(); + mKeyboardShortcutsDialog = null; + } + } + + 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(); } }); } - public void dismissKeyboardShortcutsDialog() { - if (mKeyboardShortcutsDialog != null) { - mKeyboardShortcutsDialog.dismiss(); - mKeyboardShortcutsDialog = null; + 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); } } - /** - * @return {@code true} if the keyboard shortcuts have been successfully populated. - */ - private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) { - // TODO: Populate shortcuts. - return true; + 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/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 635e66dcb07f..00b9888d69b0 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 @@ package com.android.systemui.statusbar; 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.util.AttributeSet; 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java index bed64a3d1b34..eb301204aa9d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java @@ -30,6 +30,7 @@ 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 +63,8 @@ class CarNavigationBarController { 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 +113,19 @@ class CarNavigationBarController { 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 +303,8 @@ class CarNavigationBarController { 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/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java index bf291d348162..81483c67fd8a 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 @@ public class HeaderTransformState extends TransformState { 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 @@ public class HeaderTransformState extends TransformState { 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 @@ public class HeaderTransformState extends TransformState { @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 @@ public class HeaderTransformState extends TransformState { 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 @@ public class HeaderTransformState extends TransformState { @Override public void recycle() { super.recycle(); + if (mWorkProfileState != null) { + mWorkProfileState.recycle(); + } sInstancePool.release(this); } @@ -106,6 +118,7 @@ public class HeaderTransformState extends TransformState { protected void reset() { super.reset(); mExpandButton = null; + mWorkProfileState = null; } public void setVisible(boolean visible) { @@ -125,6 +138,10 @@ public class HeaderTransformState extends TransformState { if (headerChild == mExpandButton) { headerChild.setAlpha(visible ? 1.0f : 0.0f); } + if (headerChild == mWorkProfileIcon) { + headerChild.setTranslationX(0); + headerChild.setTranslationY(0); + } } } @@ -144,6 +161,10 @@ public class HeaderTransformState extends TransformState { 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/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java index 97bf4b4c53ed..60c191126116 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 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { @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 f43a5d0cfccd..85f789ca4375 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java @@ -95,6 +95,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { @Override public void notifyContentUpdated(StatusBarNotification notification) { + super.notifyContentUpdated(notification); // Reinspect the notification. resolveHeaderViews(); updateInvertHelper(); @@ -150,6 +151,10 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { @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 3475d13188fb..9910dee0e117 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -172,6 +172,9 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp @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/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java index a1cf07e83af5..f50b9768d270 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 @@ import com.android.systemui.statusbar.TransformableView; 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 @@ public abstract class NotificationViewWrapper implements TransformableView { * @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 3e1c40aa847d..870abb7c9cc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -286,6 +286,9 @@ public class TransformState { } 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/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java index 8fa9c7e9eff4..e7e2ac2958aa 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 @@ public interface BluetoothController { 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 a04edf77ea54..6439bea104e6 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 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa 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 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa 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/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java index 7ca91a5590ae..b0369368b4b2 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 @@ public interface HotspotController { 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 5719f76a7480..61d26c72a898 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 @@ public class HotspotControllerImpl implements HotspotController { 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 @@ public class HotspotControllerImpl implements HotspotController { 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/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index 29a8981fd89e..401943e1c321 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 @@ public interface LocationController { 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 7517f97e35c6..436a40d25bfa 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 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio private AppOpsManager mAppOpsManager; private StatusBarManager mStatusBarManager; + private final int mCurrentUser; private boolean mAreActiveLocationRequests; @@ -73,6 +74,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio 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 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio * @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 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio // 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 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio /** * 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/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index e4ded67eb702..f5869b42cd65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -622,7 +622,7 @@ public class UserSwitcherController { 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/tests/Android.mk b/packages/SystemUI/tests/Android.mk index b7a41e21e7d4..964688b509c8 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -17,12 +17,15 @@ include $(CLEAR_VARS) 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 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \ 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 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ 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 03809c07ea10..2a8672dd099d 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.annotation.NonNull; 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.net.Uri; 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { 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 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { UserState userState = getCurrentUserStateLocked(); // This is a nop if UI automation is enabled. - if (userState.mUiAutomationService != null) { + if (userState.isUiAutomationSuppressingOtherServices()) { return; } @@ -1027,6 +1031,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (!mTempComponentNameSet.equals(userState.mEnabledServices)) { userState.mEnabledServices.clear(); userState.mEnabledServices.addAll(mTempComponentNameSet); + if (userState.mUiAutomationService != null) { + userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName); + } mTempComponentNameSet.clear(); return true; } @@ -3981,6 +3988,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public boolean mAccessibilityFocusOnlyInActiveWindow; private Service mUiAutomationService; + private int mUiAutomationFlags; private IAccessibilityServiceClient mUiAutomationServiceClient; private IBinder mUiAutomationServiceOwner; @@ -4044,6 +4052,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void destroyUiAutomationService() { mUiAutomationService = null; + mUiAutomationFlags = 0; mUiAutomationServiceClient = null; if (mUiAutomationServiceOwner != null) { mUiAutomationServiceOwner.unlinkToDeath( @@ -4051,6 +4060,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mUiAutomationServiceOwner = null; } } + + boolean isUiAutomationSuppressingOtherServices() { + return ((mUiAutomationService != null) && (mUiAutomationFlags + & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0); + } } private final class AccessibilityContentObserver extends ContentObserver { @@ -4130,8 +4144,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); - // We will update when the automation service dies. - if (userState.mUiAutomationService != null) { + // If the automation service is suppressing, we will update when it dies. + if (userState.isUiAutomationSuppressingOtherServices()) { return; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c3c3e3f22cd9..2d1f96b0a76b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3800,6 +3800,12 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalArgumentException("Bad timeout specified"); } + if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + .equals(networkCapabilities.getNetworkSpecifier())) { + throw new IllegalArgumentException("Invalid network specifier - must not be '" + + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'"); + } + NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java index bc12fc5c44e0..93131488f509 100644 --- a/services/core/java/com/android/server/DiskStatsService.java +++ b/services/core/java/com/android/server/DiskStatsService.java @@ -21,6 +21,7 @@ import android.os.Binder; import android.os.Environment; import android.os.StatFs; import android.os.SystemClock; +import android.os.storage.StorageManager; import java.io.File; import java.io.FileDescriptor; @@ -79,6 +80,10 @@ public class DiskStatsService extends Binder { reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw); reportFreeSpace(new File("/system"), "System", pw); + if (StorageManager.isNativeFileBasedEncryptionEnabled()) { + pw.println("File-based Encryption: true"); + } + // TODO: Read /proc/yaffs and report interesting values; // add configurable (through args) performance test parameters. } diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index e9f0a7ae63de..d0cd5365db15 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -200,7 +200,7 @@ public class LockSettingsService extends ILockSettings.Stub { 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/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index 4dc46ac63643..5aba22d5c4c7 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -16,20 +16,24 @@ package com.android.server; +import static com.android.internal.util.ArrayUtils.appendInt; + import android.app.ActivityManager; import android.content.pm.FeatureInfo; -import android.os.*; +import android.content.pm.PackageManager; +import android.os.Environment; import android.os.Process; +import android.os.storage.StorageManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; -import libcore.io.IoUtils; - import com.android.internal.util.XmlUtils; +import libcore.io.IoUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -38,8 +42,6 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; -import static com.android.internal.util.ArrayUtils.appendInt; - /** * Loads global system configuration info. */ @@ -351,10 +353,7 @@ public class SystemConfig { Slog.w(TAG, "<feature> without name in " + permFile + " at " + parser.getPositionDescription()); } else if (allowed) { - //Log.i(TAG, "Got feature " + fname); - FeatureInfo fi = new FeatureInfo(); - fi.name = fname; - mAvailableFeatures.put(fname, fi); + addFeature(fname); } XmlUtils.skipCurrentTag(parser); continue; @@ -443,10 +442,29 @@ public class SystemConfig { IoUtils.closeQuietly(permReader); } - for (String fname : mUnavailableFeatures) { - if (mAvailableFeatures.remove(fname) != null) { - Slog.d(TAG, "Removed unavailable feature " + fname); - } + // Some devices can be field-converted to FBE, so offer to splice in + // those features if not already defined by the static config + if (StorageManager.isNativeFileBasedEncryptionEnabled()) { + addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION); + addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS); + } + + for (String featureName : mUnavailableFeatures) { + removeFeature(featureName); + } + } + + private void addFeature(String featureName) { + if (!mAvailableFeatures.containsKey(featureName)) { + final FeatureInfo fi = new FeatureInfo(); + fi.name = featureName; + mAvailableFeatures.put(featureName, fi); + } + } + + private void removeFeature(String featureName) { + if (mAvailableFeatures.remove(featureName) != null) { + Slog.d(TAG, "Removed unavailable feature " + featureName); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2c55ee26cf8f..b5982c308c08 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9411,14 +9411,24 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) { + public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode, + boolean preserveWindows, boolean animate) { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()"); long ident = Binder.clearCallingIdentity(); try { synchronized (this) { - mStackSupervisor.resizeStackLocked( - stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, - !PRESERVE_WINDOWS, allowResizeInDockedMode); + if (animate) { + if (stackId == PINNED_STACK_ID) { + mWindowManager.animateResizePinnedStack(bounds); + } else { + throw new IllegalArgumentException("Stack: " + stackId + + " doesn't support animated resize."); + } + } else { + mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */, + null /* tempTaskInsetBounds */, preserveWindows, + allowResizeInDockedMode); + } } } finally { Binder.restoreCallingIdentity(ident); @@ -12960,6 +12970,9 @@ public final class ActivityManagerService extends ActivityManagerNative final StringBuilder sb = new StringBuilder(1024); appendDropBoxProcessHeaders(process, processName, sb); + 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/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 71008a9e8141..d1fcd3b9dfff 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -19,8 +19,9 @@ package com.android.server.am; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; -import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE; -import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; @@ -355,6 +356,9 @@ final class ActivityRecord { if (connections != null) { pw.print(prefix); pw.print("connections="); pw.println(connections); } + if (info != null) { + pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode)); + } } public boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) { @@ -754,11 +758,16 @@ final class ActivityRecord { } boolean isResizeable() { - return (info.flags & FLAG_RESIZEABLE) != 0; + return !isHomeActivity() && (info.resizeMode == RESIZE_MODE_RESIZEABLE + || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE); } boolean supportsPictureInPicture() { - return (info.flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0; + return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE; + } + + boolean cropAppWindows() { + return !isHomeActivity() && info.resizeMode == RESIZE_MODE_CROP_WINDOWS; } boolean isAlwaysFocusable() { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ef8d2305fb2b..3e99558faf7c 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1410,14 +1410,11 @@ final class ActivityStack { } if (mStackId == DOCKED_STACK_ID) { - // Docked stack is always visible, except in the case where the home activity - // is the top running activity in the focused home stack. - if (focusedStackId != HOME_STACK_ID) { - return STACK_VISIBLE; - } - ActivityRecord topHomeActivity = focusedStack.topRunningActivityLocked(); - return topHomeActivity == null || !topHomeActivity.isHomeActivity() ? - STACK_VISIBLE : STACK_INVISIBLE; + // Docked stack is always visible, except in the case where the top running activity in + // the focus stack doesn't support any form of resizing. + final ActivityRecord r = focusedStack.topRunningActivityLocked(); + return r == null || r.isResizeable() || r.cropAppWindows() + ? STACK_VISIBLE : STACK_INVISIBLE; } // Find the first stack below focused stack that actually got something visible. @@ -4819,7 +4816,7 @@ final class ActivityStack { r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig, - !r.isHomeActivity(), r.isAlwaysFocusable()); + r.cropAppWindows() | r.isResizeable(), r.isAlwaysFocusable()); mWindowManager.setTaskResizeable(task.taskId, task.mResizeable); r.taskConfigOverride = task.mOverrideConfig; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 8db2f8ff50f3..11dd8a38cdbf 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -98,6 +98,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Set; import static android.Manifest.permission.START_ANY_ACTIVITY; @@ -2019,7 +2020,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // If this is a forced resize, let it go through even if the bounds is not changing, // as we might need a relayout due to surface size change (to/from fullscreen). final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; - if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) { + if (Objects.equals(task.mBounds, bounds) && !forced) { // Nothing to do here... return true; } @@ -2257,10 +2258,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old // window), we need to clear the replace window settings. Otherwise, we schedule a // timeout to remove the old window if the replacing window is not coming in time. - // In case of the pinned stack we don't resize the task during the move, but we will - // resize the stack soon after so we want to retain the replacing window. - mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, - !kept || stackId == PINNED_STACK_ID); + mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept); } // The task might have already been running and its visibility needs to be synchronized with @@ -2294,7 +2292,8 @@ public final class ActivityStackSupervisor implements DisplayListener { return false; } - moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", bounds); + moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null); + mWindowManager.animateResizePinnedStack(bounds); return true; } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index fd787df25115..c9d4595cd8cd 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -24,7 +24,8 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; -import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; @@ -447,7 +448,9 @@ final class TaskRecord { } else { autoRemoveRecents = false; } - mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities; + mResizeable = info.resizeMode == RESIZE_MODE_RESIZEABLE + || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE + || mService.mForceResizableActivities; mLockTaskMode = info.lockTaskLaunchMode; mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0; setLockTaskAuth(); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 573afd67d545..033a243d2c3e 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 @@ public class InputManagerService extends IInputManager.Stub || 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 @@ public class InputManagerService extends IInputManager.Stub 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 @@ public class InputManagerService extends IInputManager.Stub // 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 @@ public class InputManagerService extends IInputManager.Stub 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 @@ public class InputManagerService extends IInputManager.Stub } } - 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 @@ public class InputManagerService extends IInputManager.Stub 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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d11da792e9d6..c3f20eb8afe1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -76,6 +76,7 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDWR; + import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT; import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 62e7fb49e082..318f966d6fcd 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.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; import android.view.InputChannel; @@ -779,15 +780,14 @@ public final class TvInputManagerService extends SystemService { } } - 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 final class TvInputManagerService extends SystemService { } } + public void setTvInputInfo(TvInputInfo inputInfo, int userId) { + String inputInfoPackageName = inputInfo.getServiceInfo().packageName; + String callingPackageName = getCallingPackageName(); + if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) { + throw new IllegalArgumentException("calling package " + callingPackageName + + " is not allowed to change TvInputInfo for " + inputInfoPackageName); + } + + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), + Binder.getCallingUid(), userId, "setTvInputInfoChanged"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + UserState userState = getOrCreateUserStateLocked(resolvedUserId); + setTvInputInfoLocked(userState, inputInfo); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + private String getCallingPackageName() { + final String[] packages = mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + if (packages != null && packages.length > 0) { + return packages[0]; + } + return "unknown"; + } + @Override public int getTvInputState(String inputId, int userId) { final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), @@ -2233,18 +2263,6 @@ public final class TvInputManagerService extends SystemService { } } } - - @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 39983dd0d303..c7d70960551e 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.ServiceInfo; 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.Display; 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 @@ import libcore.io.IoUtils; 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { */ 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final WallpaperData mWallpaper; final File mWallpaperDir; final File mWallpaperFile; + final File mWallpaperCropFile; final File mWallpaperInfoFile; public WallpaperObserver(WallpaperData wallpaper) { @@ -128,6 +134,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { int userId; - File wallpaperFile; + final File wallpaperFile; + final File cropFile; /** * Client is currently writing a new image wallpaper. @@ -199,6 +298,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } @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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + // 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { 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/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 552af03173a7..43a17c98fcc4 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -134,7 +134,7 @@ public class AppTransition implements Dump { /** Fraction of animation at which the recents thumbnail becomes completely transparent */ private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; - private static final int DEFAULT_APP_TRANSITION_DURATION = 336; + static final int DEFAULT_APP_TRANSITION_DURATION = 336; private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336; private static final long APP_TRANSITION_TIMEOUT_MS = 5000; diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java new file mode 100644 index 000000000000..5f974785b667 --- /dev/null +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -0,0 +1,142 @@ +/* + * 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.server.wm; + +import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.graphics.Rect; +import android.util.ArrayMap; +import android.util.Slog; +import android.view.animation.LinearInterpolator; + +/** + * Enables animating bounds of objects. + * + * In multi-window world bounds of both stack and tasks can change. When we need these bounds to + * change smoothly and not require the app to relaunch (e.g. because it handles resizes and + * relaunching it would cause poorer experience), these class provides a way to directly animate + * the bounds of the resized object. + * + * The object that is resized needs to implement {@link AnimateBoundsUser} interface. + */ +public class BoundsAnimationController { + private static final String TAG = TAG_WITH_CLASS_NAME ? "BoundsAnimationController" : TAG_WM; + + // Only acccessed on UI thread. + private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); + + private final class BoundsAnimator extends ValueAnimator + implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { + private final AnimateBoundsUser mTarget; + private final Rect mFrom; + private final Rect mTo; + private final Rect mTmpRect; + + BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to) { + super(); + mTarget = target; + mFrom = from; + mTo = to; + mTmpRect = new Rect(); + addUpdateListener(this); + addListener(this); + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + final float value = (Float) animation.getAnimatedValue(); + final float remains = 1 - value; + mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value); + mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value); + mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value); + mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value); + if (DEBUG_ANIM) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + ", mBounds=" + + mTmpRect + ", from=" + mFrom + ", mTo=" + mTo + ", value=" + value + + ", remains=" + remains); + if (!mTarget.setSize(mTmpRect)) { + // Whoops, the target doesn't feel like animating anymore. Let's immediately finish + // any further animation. + animation.cancel(); + } + } + + + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + finishAnimation(); + } + + @Override + public void onAnimationCancel(Animator animation) { + finishAnimation(); + } + + private void finishAnimation() { + mTarget.finishBoundsAnimation(); + removeListener(this); + removeUpdateListener(this); + mRunningAnimations.remove(mTarget); + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + } + + public interface AnimateBoundsUser { + /** + * Asks the target to directly (without any intermediate steps, like scheduling animation) + * resize its bounds. + * + * @return Whether the target still wants to be animated and successfully finished the + * operation. If it returns false, the animation will immediately be cancelled. The target + * should return false when something abnormal happened, e.g. it was completely removed + * from the hierarchy and is not valid anymore. + */ + boolean setSize(Rect bounds); + + /** + * Callback for the target to inform it that the animation is finished, so it can do some + * necessary cleanup. + */ + void finishBoundsAnimation(); + } + + void animateBounds(AnimateBoundsUser target, Rect from, Rect to) { + final BoundsAnimator existing = mRunningAnimations.get(target); + if (existing != null) { + existing.cancel(); + } + BoundsAnimator animator = new BoundsAnimator(target, from, to); + mRunningAnimations.put(target, animator); + animator.setFloatValues(0f, 1f); + animator.setDuration(DEFAULT_APP_TRANSITION_DURATION); + animator.setInterpolator(new LinearInterpolator()); + animator.start(); + } +} diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index f02e49e21977..e6fa837c75fe 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -20,6 +20,7 @@ import android.app.ActivityManager.StackId; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Debug; +import android.os.RemoteException; import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; @@ -47,7 +48,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -public class TaskStack implements DimLayer.DimLayerUser { +public class TaskStack implements DimLayer.DimLayerUser, + BoundsAnimationController.AnimateBoundsUser { // If the stack should be resized to fullscreen. private static final boolean FULLSCREEN = true; @@ -72,6 +74,12 @@ public class TaskStack implements DimLayer.DimLayerUser { /** 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; @@ -162,6 +170,85 @@ public class TaskStack implements DimLayer.DimLayerUser { 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; @@ -191,6 +278,16 @@ public class TaskStack implements DimLayer.DimLayerUser { 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; } @@ -215,9 +312,14 @@ public class TaskStack implements DimLayer.DimLayerUser { 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; } @@ -804,4 +906,32 @@ public class TaskStack implements DimLayer.DimLayerUser { } return false; } + + @Override // AnimatesBounds + public boolean setSize(Rect bounds) { + synchronized (mService.mWindowMap) { + if (mDisplayContent == null) { + return false; + } + } + try { + mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false); + } catch (RemoteException e) { + } + return true; + } + + @Override // AnimatesBounds + public void finishBoundsAnimation() { + synchronized (mService.mWindowMap) { + if (mTasks.isEmpty()) { + return; + } + final Task task = mTasks.get(mTasks.size() - 1); + if (task != null) { + task.setDragResizing(false); + mService.requestTraversal(); + } + } + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index 0979cd32a1e2..66aa8632b9a2 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 @@ public class WindowManagerDebugConfig { 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 @@ public class WindowManagerDebugConfig { 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 93a10156414a..e0e44dc4799f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -157,9 +157,11 @@ import java.util.List; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 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.PINNED_STACK_ID; 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; @@ -643,6 +645,9 @@ public class WindowManagerService extends IWindowManager.Stub final WindowAnimator mAnimator; + private final BoundsAnimationController mBoundsAnimationController = + new BoundsAnimationController(); + SparseArray<Task> mTaskIdToTask = new SparseArray<>(); /** All of the TaskStacks in the window manager, unordered. For an ordered list call @@ -2848,11 +2853,12 @@ public class WindowManagerService extends IWindowManager.Stub if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { win.prepareWindowToDisplayDuringRelayout(outConfig); } - if ((attrChanges& LayoutParams.FORMAT_CHANGED) != 0) { - // If the format can be changed in place yaay! - // If not, fall back to a surface re-build + if ((attrChanges & LayoutParams.FORMAT_CHANGED) != 0) { + // If the format can't be changed in place, preserve the old surface until the app draws + // on the new one. This prevents blinking when we change elevation of freeform and + // pinned windows. if (!winAnimator.tryChangeFormatInPlaceLocked()) { - winAnimator.destroySurfaceLocked(); + winAnimator.preserveSurfaceLocked(); result |= RELAYOUT_RES_SURFACE_CHANGED | WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; } @@ -8070,8 +8076,29 @@ public class WindowManagerService extends IWindowManager.Stub } 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; @@ -8085,7 +8112,8 @@ public class WindowManagerService extends IWindowManager.Stub break; case RESIZE_STACK: { try { - mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1); + mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false, + false); } catch (RemoteException e) { // This will not happen since we are in the same process. } @@ -10273,6 +10301,31 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void animateResizePinnedStack(final Rect bounds) { + synchronized (mWindowMap) { + final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID); + if (stack == null) { + Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found."); + return; + } + final ArrayList<Task> tasks = stack.getTasks(); + if (tasks.isEmpty()) { + Slog.w(TAG, "animateResizePinnedStack: pinned stack doesn't have any tasks."); + return; + } + final Task task = tasks.get(tasks.size() - 1); + task.setDragResizing(true); + final Rect originalBounds = new Rect(); + stack.getBounds(originalBounds); + UiThread.getHandler().post(new Runnable() { + @Override + public void run() { + mBoundsAnimationController.animateBounds(stack, originalBounds, bounds); + } + }); + } + } + public void setTaskResizeable(int taskId, boolean resizeable) { synchronized (mWindowMap) { Task task = mTaskIdToTask.get(taskId); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c541b3f6f56b..4dd2b4dfa9ad 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -57,6 +57,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import static android.app.ActivityManager.StackId; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; @@ -750,15 +751,16 @@ final class WindowState implements WindowManagerPolicy.WindowState { 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), @@ -2051,10 +2053,21 @@ final class WindowState implements WindowManagerPolicy.WindowState { // until the window to small size, otherwise the multithread renderer will shift last // one or more frame to wrong offset. So here we send fullscreen backdrop if either // isDragResizing() or isDragResizeChanged() is true. + boolean resizing = isDragResizing() || isDragResizeChanged(); + if (StackId.useWindowFrameForBackdrop(getStackId()) || !resizing) { + return frame; + } DisplayInfo displayInfo = getDisplayInfo(); mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); - boolean resizing = isDragResizing() || isDragResizeChanged(); - return (inFreeformWorkspace() || !resizing) ? frame : mTmpRect; + return mTmpRect; + } + + private int getStackId() { + final TaskStack stack = getStack(); + if (stack == null) { + return INVALID_STACK_ID; + } + return stack.mStackId; } private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, @@ -2226,7 +2239,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { } 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 cffcc5db36ff..428ab7a5eb5d 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 @@ class WindowStateAnimator { 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 236ae68eb569..ca0b43a8e7ed 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); } } - setExpirationAlarmCheckLocked(mContext, userHandle); + setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false); } } @@ -2976,8 +2998,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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( @@ -8097,11 +8118,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @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 +8134,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @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 +8148,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @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 +8162,53 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @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/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 27d52071658f..587442916d51 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -52,10 +52,12 @@ import android.net.RouteInfo; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; +import android.os.Messenger; import android.os.MessageQueue.IdleHandler; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; @@ -1298,6 +1300,36 @@ public class ConnectivityServiceTest extends AndroidTestCase { validatedCallback.expectCallback(CallbackState.LOST); } + @SmallTest + public void testInvalidNetworkSpecifier() { + boolean execptionCalled = true; + + try { + NetworkRequest.Builder builder = new NetworkRequest.Builder(); + builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER); + execptionCalled = false; + } catch (IllegalArgumentException e) { + // do nothing - should get here + } + + assertTrue("NetworkReqeuest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", + execptionCalled); + + try { + NetworkCapabilities networkCapabilities = new NetworkCapabilities(); + networkCapabilities.addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER); + mService.requestNetwork(networkCapabilities, null, 0, null, + ConnectivityManager.TYPE_WIFI); + execptionCalled = false; + } catch (IllegalArgumentException e) { + // do nothing - should get here + } + + assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", + execptionCalled); + } + private static class TestKeepaliveCallback extends PacketKeepaliveCallback { public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; 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 b4bca3eb761c..6c2fcd57023e 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.UserHandle; 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 @@ public class UserManagerTest extends AndroidTestCase { 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 81031da86af0..bfdac7e4e421 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 @@ public class UsageStatsService extends SystemService implements 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; @@ -145,7 +146,7 @@ public class UsageStatsService extends SystemService implements private long mLastAppIdleParoledTime; long mScreenOnTime; - long mScreenOnSystemTimeSnapshot; + long mLastScreenOnEventRealtime; @GuardedBy("mLock") private AppIdleHistory mAppIdleHistory = new AppIdleHistory(); @@ -188,6 +189,8 @@ public class UsageStatsService extends SystemService implements synchronized (mLock) { cleanUpRemovedUsersLocked(); + mLastScreenOnEventRealtime = SystemClock.elapsedRealtime(); + mScreenOnTime = readScreenOnTimeLocked(); } mRealTimeSnapshot = SystemClock.elapsedRealtime(); @@ -214,10 +217,6 @@ public class UsageStatsService extends SystemService implements Context.DISPLAY_SERVICE); mPowerManager = getContext().getSystemService(PowerManager.class); - mScreenOnSystemTimeSnapshot = System.currentTimeMillis(); - synchronized (mLock) { - mScreenOnTime = readScreenOnTimeLocked(); - } mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); synchronized (mLock) { updateDisplayLocked(); @@ -281,6 +280,11 @@ public class UsageStatsService extends SystemService implements } @Override + public void onStatsReloaded() { + postOneTimeCheckIdleStates(); + } + + @Override public long getAppIdleRollingWindowDurationMillis() { return mAppIdleWallclockThresholdMillis * 2; } @@ -359,6 +363,14 @@ public class UsageStatsService extends SystemService implements 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() { + mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES); + } + /** 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 +397,7 @@ public class UsageStatsService extends SystemService implements 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 +413,6 @@ public class UsageStatsService extends SystemService implements } } } - 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 +453,21 @@ public class UsageStatsService extends SystemService implements 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 +537,7 @@ public class UsageStatsService extends SystemService implements 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 +550,18 @@ public class UsageStatsService extends SystemService implements 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 +590,7 @@ public class UsageStatsService extends SystemService implements 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 +606,6 @@ public class UsageStatsService extends SystemService implements || 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 +645,7 @@ public class UsageStatsService extends SystemService implements 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 +659,6 @@ public class UsageStatsService extends SystemService implements 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 +797,7 @@ public class UsageStatsService extends SystemService implements timeNow = checkAndGetTimeLocked(); } userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - screenOnTime = getScreenOnTimeLocked(timeNow); + screenOnTime = getScreenOnTimeLocked(); } return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId, userService, timeNow, screenOnTime); @@ -865,7 +866,7 @@ public class UsageStatsService extends SystemService implements synchronized (mLock) { timeNow = checkAndGetTimeLocked(); userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - screenOnTime = getScreenOnTimeLocked(timeNow); + screenOnTime = getScreenOnTimeLocked(); } List<ApplicationInfo> apps; @@ -987,7 +988,7 @@ public class UsageStatsService extends SystemService implements */ 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 +1009,11 @@ public class UsageStatsService extends SystemService implements } 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 +1047,8 @@ public class UsageStatsService extends SystemService implements 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 +1083,14 @@ public class UsageStatsService extends SystemService implements 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 +1151,7 @@ public class UsageStatsService extends SystemService implements @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 aa2cf77b5ae1..f2045d31f69c 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 @@ class UserUsageStatsService { interface StatsUpdatedListener { void onStatsUpdated(); + void onStatsReloaded(); long getAppIdleRollingWindowDurationMillis(); } @@ -523,6 +524,9 @@ class UserUsageStatsService { 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 c65e8bac42af..84883d81533b 100644 --- a/telephony/java/android/telephony/ModemActivityInfo.java +++ b/telephony/java/android/telephony/ModemActivityInfo.java @@ -48,7 +48,9 @@ public class ModemActivityInfo implements Parcelable { 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 5dffa280fef2..069fcbf6f300 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 @@ interface ITelephonyDebug { * @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 000000000000..64eb0f1cc8f9 --- /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 000000000000..1e74b319be2e --- /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 000000000000..26d466d6beb3 --- /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/test-runner/src/android/test/ActivityInstrumentationTestCase.java b/test-runner/src/android/test/ActivityInstrumentationTestCase.java index a59ee35c2085..aca1c160ba84 100644 --- a/test-runner/src/android/test/ActivityInstrumentationTestCase.java +++ b/test-runner/src/android/test/ActivityInstrumentationTestCase.java @@ -23,15 +23,15 @@ import android.app.Activity; * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity()) * and you will then be able to manipulate your Activity directly. Most of the work is handled * automatically here by {@link #setUp} and {@link #tearDown}. - * + * * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}. - * - * @deprecated new tests should be written using + * + * @deprecated new tests should be written using * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for * configuring the Activity under test */ @Deprecated -public abstract class ActivityInstrumentationTestCase<T extends Activity> +public abstract class ActivityInstrumentationTestCase<T extends Activity> extends ActivityTestCase { String mPackage; Class<T> mActivityClass; @@ -39,7 +39,7 @@ public abstract class ActivityInstrumentationTestCase<T extends Activity> /** * Creates an {@link ActivityInstrumentationTestCase} in non-touch mode. - * + * * @param pkg ignored - no longer in use. * @param activityClass The activity to test. This must be a class in the instrumentation * targetPackage specified in the AndroidManifest.xml @@ -56,7 +56,7 @@ public abstract class ActivityInstrumentationTestCase<T extends Activity> * targetPackage specified in the AndroidManifest.xml * @param initialTouchMode true = in touch mode */ - public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass, + public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass, boolean initialTouchMode) { mActivityClass = activityClass; mInitialTouchMode = initialTouchMode; @@ -80,8 +80,8 @@ public abstract class ActivityInstrumentationTestCase<T extends Activity> protected void tearDown() throws Exception { getActivity().finish(); setActivity(null); - - // Scrub out members - protects against memory leaks in the case where someone + + // Scrub out members - protects against memory leaks in the case where someone // creates a non-static inner class (thus referencing the test case) and gives it to // someone else to hold onto scrubClass(ActivityInstrumentationTestCase.class); diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java index c4bcf312ad9c..0e61ce727c40 100644 --- a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java +++ b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java @@ -25,26 +25,26 @@ import java.lang.reflect.Method; * This class provides functional testing of a single activity. The activity under test will * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity()) * and you will then be able to manipulate your Activity directly. - * + * * <p>Other options supported by this test case include: * <ul> * <li>You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).</li> - * <li>You can inject custom Intents into your Activity (see + * <li>You can inject custom Intents into your Activity (see * {@link #setActivityIntent(Intent)}).</li> * </ul> - * + * * <p>This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated. * New tests should be written using this base class. - * + * * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}. * - * <div class="special reference"> - * <h3>Developer Guides</h3> - * <p>For more information about application testing, read the - * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p> - * </div> + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html"> + * ActivityTestRule</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ -public abstract class ActivityInstrumentationTestCase2<T extends Activity> +@Deprecated +public abstract class ActivityInstrumentationTestCase2<T extends Activity> extends ActivityTestCase { Class<T> mActivityClass; boolean mInitialTouchMode = false; @@ -78,18 +78,18 @@ public abstract class ActivityInstrumentationTestCase2<T extends Activity> * Get the Activity under test, starting it if necessary. * * For each test method invocation, the Activity will not actually be created until the first - * time this method is called. - * - * <p>If you wish to provide custom setup values to your Activity, you may call - * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)} - * before your first call to getActivity(). Calling them after your Activity has + * time this method is called. + * + * <p>If you wish to provide custom setup values to your Activity, you may call + * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)} + * before your first call to getActivity(). Calling them after your Activity has * started will have no effect. * * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread. * If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity * will be started automatically just before your test method is run. You still call this * method in order to get the Activity under test. - * + * * @return the Activity under test */ @Override @@ -113,10 +113,10 @@ public abstract class ActivityInstrumentationTestCase2<T extends Activity> /** * Call this method before the first call to {@link #getActivity} to inject a customized Intent * into the Activity under test. - * + * * <p>If you do not call this, the default intent will be provided. If you call this after * your Activity has been started, it will have no effect. - * + * * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread. * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call * {@link #setActivityIntent(Intent)} from {@link #setUp()}. @@ -131,28 +131,28 @@ public abstract class ActivityInstrumentationTestCase2<T extends Activity> public void setActivityIntent(Intent i) { mActivityIntent = i; } - + /** * Call this method before the first call to {@link #getActivity} to set the initial touch * mode for the Activity under test. - * + * * <p>If you do not call this, the touch mode will be false. If you call this after * your Activity has been started, it will have no effect. - * + * * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread. * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call * {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}. - * + * * @param initialTouchMode true if the Activity should be placed into "touch mode" when started */ public void setActivityInitialTouchMode(boolean initialTouchMode) { mInitialTouchMode = initialTouchMode; } - + @Override protected void setUp() throws Exception { super.setUp(); - + mInitialTouchMode = false; mActivityIntent = null; } @@ -165,8 +165,8 @@ public abstract class ActivityInstrumentationTestCase2<T extends Activity> a.finish(); setActivity(null); } - - // Scrub out members - protects against memory leaks in the case where someone + + // Scrub out members - protects against memory leaks in the case where someone // creates a non-static inner class (thus referencing the test case) and gives it to // someone else to hold onto scrubClass(ActivityInstrumentationTestCase2.class); diff --git a/test-runner/src/android/test/ActivityTestCase.java b/test-runner/src/android/test/ActivityTestCase.java index c7b1d7017fc2..51dd3ef8c35b 100644 --- a/test-runner/src/android/test/ActivityTestCase.java +++ b/test-runner/src/android/test/ActivityTestCase.java @@ -25,7 +25,11 @@ import java.lang.reflect.Modifier; * This is common code used to support Activity test cases. For more useful classes, please see * {@link android.test.ActivityUnitTestCase} and * {@link android.test.ActivityInstrumentationTestCase}. + * + * @deprecated New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public abstract class ActivityTestCase extends InstrumentationTestCase { /** diff --git a/test-runner/src/android/test/ActivityUnitTestCase.java b/test-runner/src/android/test/ActivityUnitTestCase.java index 40cca90d1b42..a191445d8af5 100644 --- a/test-runner/src/android/test/ActivityUnitTestCase.java +++ b/test-runner/src/android/test/ActivityUnitTestCase.java @@ -32,14 +32,14 @@ import android.util.Log; /** * This class provides isolated testing of a single activity. The activity under test will - * be created with minimal connection to the system infrastructure, and you can inject mocked or + * be created with minimal connection to the system infrastructure, and you can inject mocked or * wrappered versions of many of Activity's dependencies. Most of the work is handled * automatically here by {@link #setUp} and {@link #tearDown}. - * + * * <p>If you prefer a functional test, see {@link android.test.ActivityInstrumentationTestCase}. - * + * * <p>It must be noted that, as a true unit test, your Activity will not be running in the - * normal system and will not participate in the normal interactions with other Activities. + * normal system and will not participate in the normal interactions with other Activities. * The following methods should not be called in this configuration - most of them will throw * exceptions: * <ul> @@ -54,17 +54,17 @@ import android.util.Log; * <li>{@link android.app.Activity#isTaskRoot()}</li> * <li>{@link android.app.Activity#moveTaskToBack(boolean)}</li> * </ul> - * - * <p>The following methods may be called but will not do anything. For test purposes, you can use - * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to + * + * <p>The following methods may be called but will not do anything. For test purposes, you can use + * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to * inspect the parameters that they were called with. * <ul> * <li>{@link android.app.Activity#startActivity(Intent)}</li> * <li>{@link android.app.Activity#startActivityForResult(Intent, int)}</li> * </ul> * - * <p>The following methods may be called but will not do anything. For test purposes, you can use - * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the + * <p>The following methods may be called but will not do anything. For test purposes, you can use + * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the * parameters that they were called with. * <ul> * <li>{@link android.app.Activity#finish()}</li> @@ -72,8 +72,12 @@ import android.util.Log; * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li> * </ul> * + * @deprecated Write + * <a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html">Local Unit Tests</a> + * instead. */ -public abstract class ActivityUnitTestCase<T extends Activity> +@Deprecated +public abstract class ActivityUnitTestCase<T extends Activity> extends ActivityTestCase { private static final String TAG = "ActivityUnitTestCase"; @@ -102,31 +106,31 @@ public abstract class ActivityUnitTestCase<T extends Activity> // default value for target context, as a default mActivityContext = getInstrumentation().getTargetContext(); } - + /** * Start the activity under test, in the same way as if it was started by - * {@link android.content.Context#startActivity Context.startActivity()}, providing the + * {@link android.content.Context#startActivity Context.startActivity()}, providing the * arguments it supplied. When you use this method to start the activity, it will automatically * be stopped by {@link #tearDown}. - * - * <p>This method will call onCreate(), but if you wish to further exercise Activity life + * + * <p>This method will call onCreate(), but if you wish to further exercise Activity life * cycle methods, you must call them yourself from your test case. - * + * * <p><i>Do not call from your setUp() method. You must call this method from each of your * test methods.</i> - * + * * @param intent The Intent as if supplied to {@link android.content.Context#startActivity}. * @param savedInstanceState The instance state, if you are simulating this part of the life * cycle. Typically null. - * @param lastNonConfigurationInstance This Object will be available to the - * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}. + * @param lastNonConfigurationInstance This Object will be available to the + * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}. * Typically null. * @return Returns the Activity that was created */ protected T startActivity(Intent intent, Bundle savedInstanceState, Object lastNonConfigurationInstance) { assertFalse("Activity already created", mCreated); - + if (!mAttached) { assertNotNull(mActivityClass); setActivity(null); @@ -154,7 +158,7 @@ public abstract class ActivityUnitTestCase<T extends Activity> assertNotNull(newActivity); setActivity(newActivity); - + mAttached = true; } @@ -165,22 +169,22 @@ public abstract class ActivityUnitTestCase<T extends Activity> } return result; } - + @Override protected void tearDown() throws Exception { - + setActivity(null); - - // Scrub out members - protects against memory leaks in the case where someone + + // Scrub out members - protects against memory leaks in the case where someone // creates a non-static inner class (thus referencing the test case) and gives it to // someone else to hold onto scrubClass(ActivityInstrumentationTestCase.class); super.tearDown(); } - + /** - * Set the application for use during the test. You must call this function before calling + * Set the application for use during the test. You must call this function before calling * {@link #startActivity}. If your test does not call this method, * @param application The Application object that will be injected into the Activity under test. */ @@ -198,7 +202,7 @@ public abstract class ActivityUnitTestCase<T extends Activity> } /** - * This method will return the value if your Activity under test calls + * This method will return the value if your Activity under test calls * {@link android.app.Activity#setRequestedOrientation}. */ public int getRequestedOrientation() { @@ -207,10 +211,10 @@ public abstract class ActivityUnitTestCase<T extends Activity> } return 0; } - + /** - * This method will return the launch intent if your Activity under test calls - * {@link android.app.Activity#startActivity(Intent)} or + * This method will return the launch intent if your Activity under test calls + * {@link android.app.Activity#startActivity(Intent)} or * {@link android.app.Activity#startActivityForResult(Intent, int)}. * @return The Intent provided in the start call, or null if no start call was made. */ @@ -220,9 +224,9 @@ public abstract class ActivityUnitTestCase<T extends Activity> } return null; } - + /** - * This method will return the launch request code if your Activity under test calls + * This method will return the launch request code if your Activity under test calls * {@link android.app.Activity#startActivityForResult(Intent, int)}. * @return The request code provided in the start call, or -1 if no start call was made. */ @@ -234,9 +238,9 @@ public abstract class ActivityUnitTestCase<T extends Activity> } /** - * This method will notify you if the Activity under test called - * {@link android.app.Activity#finish()}, - * {@link android.app.Activity#finishFromChild(Activity)}, or + * This method will notify you if the Activity under test called + * {@link android.app.Activity#finish()}, + * {@link android.app.Activity#finishFromChild(Activity)}, or * {@link android.app.Activity#finishActivity(int)}. * @return Returns true if one of the listed finish methods was called. */ @@ -246,9 +250,9 @@ public abstract class ActivityUnitTestCase<T extends Activity> } return false; } - + /** - * This method will return the request code if the Activity under test called + * This method will return the request code if the Activity under test called * {@link android.app.Activity#finishActivity(int)}. * @return The request code provided in the start call, or -1 if no finish call was made. */ @@ -258,7 +262,7 @@ public abstract class ActivityUnitTestCase<T extends Activity> } return 0; } - + /** * This mock Activity represents the "parent" activity. By injecting this, we allow the user * to call a few more Activity methods, including: @@ -269,7 +273,7 @@ public abstract class ActivityUnitTestCase<T extends Activity> * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li> * <li>{@link android.app.Activity#finishFromChild(Activity child)}</li> * </ul> - * + * * TODO: Make this overrideable, and the unit test can look for calls to other methods */ private static class MockParent extends Activity { @@ -303,7 +307,7 @@ public abstract class ActivityUnitTestCase<T extends Activity> public Window getWindow() { return null; } - + /** * By defining this in the parent, we allow the tested activity to call * <ul> @@ -316,7 +320,7 @@ public abstract class ActivityUnitTestCase<T extends Activity> mStartedActivityIntent = intent; mStartedActivityRequest = requestCode; } - + /** * By defining this in the parent, we allow the tested activity to call * <ul> diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java index aa7c677c968f..50eaafbae39d 100644 --- a/test-runner/src/android/test/AndroidTestRunner.java +++ b/test-runner/src/android/test/AndroidTestRunner.java @@ -33,6 +33,13 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.List; +/** + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> + * AndroidJUnitRunner</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. + */ +@Deprecated public class AndroidTestRunner extends BaseTestRunner { private TestResult mTestResult; diff --git a/test-runner/src/android/test/ApplicationTestCase.java b/test-runner/src/android/test/ApplicationTestCase.java index f0931814ff7d..4d73f5300840 100644 --- a/test-runner/src/android/test/ApplicationTestCase.java +++ b/test-runner/src/android/test/ApplicationTestCase.java @@ -32,7 +32,7 @@ import android.content.Context; * In order to support the lifecycle of a Application, this test case will make the * following calls at the following times. * - * <ul><li>The test case will not call onCreate() until your test calls + * <ul><li>The test case will not call onCreate() until your test calls * {@link #createApplication()}. This gives you a chance * to set up or adjust any additional framework or test logic before * onCreate().</li> @@ -40,22 +40,28 @@ import android.content.Context; * automatically called, and it will stop & destroy your application by calling its * onDestroy() method.</li> * </ul> - * + * * <p><b>Dependency Injection.</b> * Every Application has one inherent dependency, the {@link android.content.Context Context} in * which it runs. - * This framework allows you to inject a modified, mock, or isolated replacement for this + * This framework allows you to inject a modified, mock, or isolated replacement for this * dependencies, and thus perform a true unit test. - * + * * <p>If simply run your tests as-is, your Application will be injected with a fully-functional * Context. - * You can create and inject alternative types of Contexts by calling + * You can create and inject alternative types of Contexts by calling * {@link AndroidTestCase#setContext(Context) setContext()}. You must do this <i>before</i> calling * {@link #createApplication()}. The test framework provides a - * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext}, - * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and + * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext}, + * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and * {@link android.content.ContextWrapper ContextWrapper}. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html"> + * InstrumentationRegistry</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public abstract class ApplicationTestCase<T extends Application> extends AndroidTestCase { Class<T> mApplicationClass; @@ -78,17 +84,17 @@ public abstract class ApplicationTestCase<T extends Application> extends Android } /** - * This will do the work to instantiate the Application under test. After this, your test + * This will do the work to instantiate the Application under test. After this, your test * code must also start and stop the Application. */ @Override protected void setUp() throws Exception { super.setUp(); - + // get the real context, before the individual tests have a chance to muck with it mSystemContext = getContext(); } - + /** * Load and attach the application under test. */ @@ -101,26 +107,26 @@ public abstract class ApplicationTestCase<T extends Application> extends Android } mAttached = true; } - + /** - * Start the Application under test, in the same way as if it was started by the system. + * Start the Application under test, in the same way as if it was started by the system. * If you use this method to start the Application, it will automatically * be stopped by {@link #tearDown}. If you wish to inject a specialized Context for your - * test, by calling {@link AndroidTestCase#setContext(Context) setContext()}, + * test, by calling {@link AndroidTestCase#setContext(Context) setContext()}, * you must do so before calling this method. */ final protected void createApplication() { assertFalse(mCreated); - + if (!mAttached) { setupApplication(); } assertNotNull(mApplication); - + mApplication.onCreate(); mCreated = true; } - + /** * This will make the necessary calls to terminate the Application under test (it will * call onTerminate(). Ordinarily this will be called automatically (by {@link #tearDown}, but @@ -131,13 +137,13 @@ public abstract class ApplicationTestCase<T extends Application> extends Android mApplication.onTerminate(); } } - + /** - * Shuts down the Application under test. Also makes sure all resources are cleaned up and + * Shuts down the Application under test. Also makes sure all resources are cleaned up and * garbage collected before moving on to the next * test. Subclasses that override this method should make sure they call super.tearDown() * at the end of the overriding method. - * + * * @throws Exception */ @Override @@ -145,7 +151,7 @@ public abstract class ApplicationTestCase<T extends Application> extends Android terminateApplication(); mApplication = null; - // Scrub out members - protects against memory leaks in the case where someone + // Scrub out members - protects against memory leaks in the case where someone // creates a non-static inner class (thus referencing the test case) and gives it to // someone else to hold onto scrubClass(ApplicationTestCase.class); @@ -156,7 +162,7 @@ public abstract class ApplicationTestCase<T extends Application> extends Android /** * Return a real (not mocked or instrumented) system Context that can be used when generating * Mock or other Context objects for your Application under test. - * + * * @return Returns a reference to a normal Context. */ public Context getSystemContext() { @@ -165,7 +171,7 @@ public abstract class ApplicationTestCase<T extends Application> extends Android /** * This test simply confirms that the Application class can be instantiated properly. - * + * * @throws Exception */ final public void testApplicationTestCaseSetUpProperly() throws Exception { diff --git a/test-runner/src/android/test/AssertionFailedError.java b/test-runner/src/android/test/AssertionFailedError.java index b3ac6d145ab8..fc3e98e965c7 100644 --- a/test-runner/src/android/test/AssertionFailedError.java +++ b/test-runner/src/android/test/AssertionFailedError.java @@ -18,17 +18,18 @@ package android.test; /** * Thrown when an assertion failed. - * + * * @deprecated use junit.framework.AssertionFailedError */ +@Deprecated public class AssertionFailedError extends Error { - + /** * It is more typical to call {@link #AssertionFailedError(String)}. */ public AssertionFailedError() { } - + public AssertionFailedError(String errorMessage) { super(errorMessage); } diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java index 1f6e64780b81..1ab7c7faeca4 100644 --- a/test-runner/src/android/test/ClassPathPackageInfo.java +++ b/test-runner/src/android/test/ClassPathPackageInfo.java @@ -24,9 +24,10 @@ import java.util.Set; /** * The Package object doesn't allow you to iterate over the contained * classes and subpackages of that package. This is a version that does. - * + * * {@hide} Not needed for 1.0 SDK. */ +@Deprecated public class ClassPathPackageInfo { private final ClassPathPackageInfoSource source; diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java index 0ffecdb8e969..89bb494e02dd 100644 --- a/test-runner/src/android/test/ClassPathPackageInfoSource.java +++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java @@ -33,9 +33,10 @@ import java.util.zip.ZipFile; /** * Generate {@link ClassPathPackageInfo}s by scanning apk paths. - * + * * {@hide} Not needed for 1.0 SDK. */ +@Deprecated public class ClassPathPackageInfoSource { private static final String CLASS_EXTENSION = ".class"; @@ -82,7 +83,7 @@ public class ClassPathPackageInfoSource { // Don't try to load classes that are generated. They usually aren't in test apks. continue; } - + try { // We get errors in the emulator if we don't use the caller's class loader. topLevelClasses.add(Class.forName(className, false, diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java index 23e0aba677a4..42ef48b38a24 100644 --- a/test-runner/src/android/test/DatabaseTestUtils.java +++ b/test-runner/src/android/test/DatabaseTestUtils.java @@ -27,6 +27,7 @@ import java.util.Set; * A collection of utilities for writing unit tests for database code. * @hide pending API council approval */ +@Deprecated public class DatabaseTestUtils { /** diff --git a/test-runner/src/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java index 655a65c1c0f8..2b05e4a877b3 100644 --- a/test-runner/src/android/test/InstrumentationCoreTestRunner.java +++ b/test-runner/src/android/test/InstrumentationCoreTestRunner.java @@ -41,6 +41,7 @@ import android.util.Log; * * @hide */ +@Deprecated public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { /** diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java index db80ef951570..9bd4c966496d 100644 --- a/test-runner/src/android/test/InstrumentationTestRunner.java +++ b/test-runner/src/android/test/InstrumentationTestRunner.java @@ -155,6 +155,10 @@ import junit.textui.ResultPrinter; * -e coverageFile /sdcard/myFile.ec * <br/> * in addition to the other arguments. + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> + * AndroidJUnitRunner</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ /* (not JavaDoc) @@ -170,6 +174,7 @@ import junit.textui.ResultPrinter; * * This model is used by many existing app tests, but can probably be deprecated. */ +@Deprecated public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider { /** @hide */ diff --git a/test-runner/src/android/test/InstrumentationUtils.java b/test-runner/src/android/test/InstrumentationUtils.java index 1a7002ab4844..cc508132ba21 100644 --- a/test-runner/src/android/test/InstrumentationUtils.java +++ b/test-runner/src/android/test/InstrumentationUtils.java @@ -17,17 +17,17 @@ package android.test; /** - * * The InstrumentationUtils class has all the utility functions needed for * instrumentation tests. * * {@hide} - Not currently used. */ +@Deprecated public class InstrumentationUtils { /** * An utility function that returns the menu identifier for a particular * menu item. - * + * * @param cls Class object of the class that handles the menu ite,. * @param identifier Menu identifier. * @return The integer corresponding to the menu item. @@ -35,7 +35,7 @@ public class InstrumentationUtils { public static int getMenuIdentifier(Class cls, String identifier) { int id = -1; try { - Integer field = (Integer)cls.getDeclaredField(identifier).get(cls); + Integer field = (Integer)cls.getDeclaredField(identifier).get(cls); id = field.intValue(); } catch (NoSuchFieldException e) { e.printStackTrace(); diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java index f971b5ded187..3abf38f3b224 100644 --- a/test-runner/src/android/test/IsolatedContext.java +++ b/test-runner/src/android/test/IsolatedContext.java @@ -43,9 +43,13 @@ import java.util.List; /** - * A mock context which prevents its users from talking to the rest of the device while + * A mock context which prevents its users from talking to the rest of the device while * stubbing enough methods to satify code that tries to talk to other packages. + * + * @deprecated New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class IsolatedContext extends ContextWrapper { private ContentResolver mResolver; diff --git a/test-runner/src/android/test/LaunchPerformanceBase.java b/test-runner/src/android/test/LaunchPerformanceBase.java index d423e624193d..62c90d6a4373 100644 --- a/test-runner/src/android/test/LaunchPerformanceBase.java +++ b/test-runner/src/android/test/LaunchPerformanceBase.java @@ -26,6 +26,7 @@ import android.os.Bundle; * * @hide */ +@Deprecated public class LaunchPerformanceBase extends Instrumentation { public static final String LOG_TAG = "Launch Performance"; @@ -39,7 +40,7 @@ public class LaunchPerformanceBase extends Instrumentation { mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); setAutomaticPerformanceSnapshots(); } - + /** * Launches intent, and waits for idle before returning. * diff --git a/test-runner/src/android/test/MoreAsserts.java b/test-runner/src/android/test/MoreAsserts.java index 33648953e57d..d33911a186cc 100644 --- a/test-runner/src/android/test/MoreAsserts.java +++ b/test-runner/src/android/test/MoreAsserts.java @@ -30,7 +30,10 @@ import java.util.regex.Pattern; /** * Contains additional assertion methods not found in JUnit. + * @deprecated Use + * <a href="https://github.com/hamcrest">Hamcrest matchers</a> instead. */ +@Deprecated public final class MoreAsserts { private MoreAsserts() { } @@ -375,7 +378,7 @@ public final class MoreAsserts { failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")"); } } - + if (expectedMap.size() > 0) { failWithMessage(message, "Extra objects in expected."); } diff --git a/test-runner/src/android/test/NoExecTestResult.java b/test-runner/src/android/test/NoExecTestResult.java index 1ee62c169090..a01b6aad3a38 100644 --- a/test-runner/src/android/test/NoExecTestResult.java +++ b/test-runner/src/android/test/NoExecTestResult.java @@ -19,11 +19,12 @@ import junit.framework.TestCase; import junit.framework.TestResult; /** - * A benign test result that does no actually test execution, just runs + * A benign test result that does no actually test execution, just runs * through the motions - * + * * {@hide} Not needed for SDK. */ +@Deprecated class NoExecTestResult extends TestResult { /** diff --git a/test-runner/src/android/test/PackageInfoSources.java b/test-runner/src/android/test/PackageInfoSources.java index ef3744911956..205f86b04d5f 100644 --- a/test-runner/src/android/test/PackageInfoSources.java +++ b/test-runner/src/android/test/PackageInfoSources.java @@ -19,6 +19,7 @@ package android.test; /** * {@hide} Not needed for SDK. */ +@Deprecated public class PackageInfoSources { private static ClassPathPackageInfoSource classPathSource; diff --git a/test-runner/src/android/test/PerformanceCollectorTestCase.java b/test-runner/src/android/test/PerformanceCollectorTestCase.java index 4309ff73eb5f..3a5dafc0db75 100644 --- a/test-runner/src/android/test/PerformanceCollectorTestCase.java +++ b/test-runner/src/android/test/PerformanceCollectorTestCase.java @@ -30,6 +30,7 @@ import android.os.PerformanceCollector.PerformanceResultsWriter; * * {@hide} Not needed for SDK. */ +@Deprecated public interface PerformanceCollectorTestCase { public PerformanceCollector mPerfCollector = new PerformanceCollector(); diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java index 3c4da9e82f81..36786b09df26 100644 --- a/test-runner/src/android/test/RenamingDelegatingContext.java +++ b/test-runner/src/android/test/RenamingDelegatingContext.java @@ -36,7 +36,11 @@ import java.util.Set; * This is a class which delegates to the given context, but performs database * and file operations with a renamed database/file name (prefixes default * names with a given prefix). + * + * @deprecated New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class RenamingDelegatingContext extends ContextWrapper { private Context mFileContext; @@ -168,7 +172,7 @@ public class RenamingDelegatingContext extends ContextWrapper { return false; } } - + @Override public File getDatabasePath(String name) { return mFileContext.getDatabasePath(renamedFileName(name)); @@ -216,7 +220,7 @@ public class RenamingDelegatingContext extends ContextWrapper { public String[] fileList() { return mFileNames.toArray(new String[]{}); } - + /** * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real * one) and return it instead. This code is basically getCacheDir(), except it uses the real @@ -241,21 +245,4 @@ public class RenamingDelegatingContext extends ContextWrapper { } return mCacheDir; } - - -// /** -// * Given an array of files returns only those whose names indicate that they belong to this -// * context. -// * @param allFiles the original list of files -// * @return the pruned list of files -// */ -// private String[] prunedFileList(String[] allFiles) { -// List<String> files = Lists.newArrayList(); -// for (String file : allFiles) { -// if (file.startsWith(mFilePrefix)) { -// files.add(file); -// } -// } -// return files.toArray(new String[]{}); -// } } diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java index ba20c0980e7a..c8ff0f904d6d 100644 --- a/test-runner/src/android/test/ServiceTestCase.java +++ b/test-runner/src/android/test/ServiceTestCase.java @@ -92,7 +92,13 @@ import java.util.Random; * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, * {@link android.content.ContextWrapper ContextWrapper}, and * {@link android.test.IsolatedContext}. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html"> + * ServiceTestRule</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase { Class<T> mServiceClass; diff --git a/test-runner/src/android/test/SimpleCache.java b/test-runner/src/android/test/SimpleCache.java index 44424ec56918..46143e4879b8 100644 --- a/test-runner/src/android/test/SimpleCache.java +++ b/test-runner/src/android/test/SimpleCache.java @@ -19,6 +19,7 @@ package android.test; import java.util.HashMap; import java.util.Map; +@Deprecated abstract class SimpleCache<K, V> { private Map<K, V> map = new HashMap<K, V>(); diff --git a/test-runner/src/android/test/SingleLaunchActivityTestCase.java b/test-runner/src/android/test/SingleLaunchActivityTestCase.java index 72c93cef3fde..af1448e55678 100644 --- a/test-runner/src/android/test/SingleLaunchActivityTestCase.java +++ b/test-runner/src/android/test/SingleLaunchActivityTestCase.java @@ -22,13 +22,19 @@ import android.app.Activity; * If you would like to test a single activity with an * {@link android.test.InstrumentationTestCase}, this provides some of the boiler plate to * launch and finish the activity in {@link #setUp} and {@link #tearDown}. - * - * This launches the activity only once for the entire class instead of doing it + * + * This launches the activity only once for the entire class instead of doing it * in every setup / teardown call. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html"> + * ActivityTestRule</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public abstract class SingleLaunchActivityTestCase<T extends Activity> extends InstrumentationTestCase { - + String mPackage; Class<T> mActivityClass; private static int sTestCaseCounter = 0; @@ -44,10 +50,10 @@ public abstract class SingleLaunchActivityTestCase<T extends Activity> */ public SingleLaunchActivityTestCase(String pkg, Class<T> activityClass) { mPackage = pkg; - mActivityClass = activityClass; - sTestCaseCounter ++; + mActivityClass = activityClass; + sTestCaseCounter ++; } - + /** * The activity that will be set up for use in each test method. */ @@ -66,7 +72,7 @@ public abstract class SingleLaunchActivityTestCase<T extends Activity> getInstrumentation().setInTouchMode(false); sActivity = launchActivity(mPackage, mActivityClass, null); sActivityLaunchedFlag = true; - } + } } @Override @@ -75,7 +81,7 @@ public abstract class SingleLaunchActivityTestCase<T extends Activity> sTestCaseCounter --; if (sTestCaseCounter == 0) { sActivity.finish(); - } + } super.tearDown(); } diff --git a/test-runner/src/android/test/SyncBaseInstrumentation.java b/test-runner/src/android/test/SyncBaseInstrumentation.java index 7d418f09ead9..de36b4ff013f 100644 --- a/test-runner/src/android/test/SyncBaseInstrumentation.java +++ b/test-runner/src/android/test/SyncBaseInstrumentation.java @@ -27,7 +27,13 @@ import android.accounts.Account; * If you would like to test sync a single provider with an * {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and * {@link #tearDown}. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html"> + * InstrumentationRegistry</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class SyncBaseInstrumentation extends InstrumentationTestCase { private Context mTargetContext; ContentResolver mContentResolver; diff --git a/test-runner/src/android/test/TestCase.java b/test-runner/src/android/test/TestCase.java index 5432ce85463b..b234f441c5c2 100644 --- a/test-runner/src/android/test/TestCase.java +++ b/test-runner/src/android/test/TestCase.java @@ -23,14 +23,13 @@ import android.content.Context; * More complex interface for test cases. * * <p>Just implementing Runnable is enough for many test cases. If you - * have additional setup or teardown, this interface might be for you, + * have additional setup or teardown, this interface might be for you, * especially if you need to share it between different test cases, or your * teardown code must execute regardless of whether your test passed. * * <p>See the android.test package documentation (click the more... link) * for a full description */ - @Deprecated public interface TestCase extends Runnable { diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java index 3ba97118e56b..c46d403f1350 100644 --- a/test-runner/src/android/test/TestCaseUtil.java +++ b/test-runner/src/android/test/TestCaseUtil.java @@ -35,6 +35,7 @@ import java.util.Set; * @hide - This is part of a framework that is under development and should not be used for * active development. */ +@Deprecated public class TestCaseUtil { private TestCaseUtil() { @@ -67,7 +68,7 @@ public class TestCaseUtil { */ if (test instanceof TestCase && ((TestCase)test).getName() == null) { - workingTest = invokeSuiteMethodIfPossible(test.getClass(), + workingTest = invokeSuiteMethodIfPossible(test.getClass(), seen); } if (workingTest == null) { @@ -155,7 +156,7 @@ public class TestCaseUtil { public static TestSuite createTestSuite(Class<? extends Test> testClass) throws InstantiationException, IllegalAccessException { - Test test = invokeSuiteMethodIfPossible(testClass, + Test test = invokeSuiteMethodIfPossible(testClass, new HashSet<Class<?>>()); if (test == null) { return new TestSuite(testClass); diff --git a/test-runner/src/android/test/TestPrinter.java b/test-runner/src/android/test/TestPrinter.java index 37bd721c9bab..a23f06dde9b0 100644 --- a/test-runner/src/android/test/TestPrinter.java +++ b/test-runner/src/android/test/TestPrinter.java @@ -30,9 +30,10 @@ import java.util.Set; * probably will not need to create or extend this class or call its methods manually. * See the full {@link android.test} package description for information about * getting test results. - * + * * {@hide} Not needed for 1.0 SDK. */ +@Deprecated public class TestPrinter implements TestRunner.Listener, TestListener { private String mTag; @@ -89,7 +90,7 @@ public class TestPrinter implements TestRunner.Listener, TestListener { mFailedTests.add(test.toString()); failed(test.toString(), t); } - + public void addError(Test test, Throwable t) { failed(test, t); } diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java index 012df3501026..beecc6fdd9de 100644 --- a/test-runner/src/android/test/TestRunner.java +++ b/test-runner/src/android/test/TestRunner.java @@ -42,6 +42,7 @@ import com.google.android.collect.Lists; * * {@hide} Not needed for 1.0 SDK. */ +@Deprecated public class TestRunner implements PerformanceTestCase.Intermediates { public static final int REGRESSION = 0; public static final int PERFORMANCE = 1; diff --git a/test-runner/src/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java index dc9ce6e3bc10..c74651cea01f 100644 --- a/test-runner/src/android/test/TestSuiteProvider.java +++ b/test-runner/src/android/test/TestSuiteProvider.java @@ -21,6 +21,7 @@ import junit.framework.TestSuite; /** * Implementors will know how to get a test suite. */ +@Deprecated public interface TestSuiteProvider { TestSuite getTestSuite(); diff --git a/test-runner/src/android/test/TimedTest.java b/test-runner/src/android/test/TimedTest.java index 95cc9bffd42c..cb15ef907050 100644 --- a/test-runner/src/android/test/TimedTest.java +++ b/test-runner/src/android/test/TimedTest.java @@ -30,6 +30,7 @@ import java.lang.annotation.RetentionPolicy; * * {@hide} Pending approval for public API. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) public @interface TimedTest { boolean includeDetailedStats() default false; diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java index 1b854b069ec0..28dc7b2f900c 100644 --- a/test-runner/src/android/test/TouchUtils.java +++ b/test-runner/src/android/test/TouchUtils.java @@ -31,9 +31,15 @@ import android.view.ViewGroup; * Reusable methods for generating touch events. These methods can be used with * InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with * the application through a touch screen. + * + * @deprecated Use + * <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso UI testing + * framework</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class TouchUtils { - + /** * Simulate touching in the center of the screen and dragging one quarter of the way down * @param test The test case that is being run @@ -46,7 +52,7 @@ public class TouchUtils { public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) { dragQuarterScreenDown(test, test.getActivity()); } - + /** * Simulate touching in the center of the screen and dragging one quarter of the way down * @param test The test case that is being run @@ -56,14 +62,14 @@ public class TouchUtils { Display display = activity.getWindowManager().getDefaultDisplay(); final Point size = new Point(); display.getSize(size); - + final float x = size.x / 2.0f; final float fromY = size.y * 0.5f; final float toY = size.y * 0.75f; - + drag(test, x, x, fromY, toY, 4); } - + /** * Simulate touching in the center of the screen and dragging one quarter of the way up * @param test The test case that is being run @@ -76,7 +82,7 @@ public class TouchUtils { public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) { dragQuarterScreenUp(test, test.getActivity()); } - + /** * Simulate touching in the center of the screen and dragging one quarter of the way up * @param test The test case that is being run @@ -86,18 +92,18 @@ public class TouchUtils { Display display = activity.getWindowManager().getDefaultDisplay(); final Point size = new Point(); display.getSize(size); - + final float x = size.x / 2.0f; final float fromY = size.y * 0.5f; final float toY = size.y * 0.25f; - + drag(test, x, x, fromY, toY, 4); } - + /** * Scroll a ViewGroup to the bottom by repeatedly calling * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)} - * + * * @param test The test case that is being run * @param v The ViewGroup that should be dragged * @@ -109,11 +115,11 @@ public class TouchUtils { public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) { scrollToBottom(test, test.getActivity(), v); } - + /** * Scroll a ViewGroup to the bottom by repeatedly calling * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)} - * + * * @param test The test case that is being run * @param activity The activity that is in the foreground of the test case * @param v The ViewGroup that should be dragged @@ -132,7 +138,7 @@ public class TouchUtils { /** * Scroll a ViewGroup to the top by repeatedly calling * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)} - * + * * @param test The test case that is being run * @param v The ViewGroup that should be dragged * @@ -144,11 +150,11 @@ public class TouchUtils { public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) { scrollToTop(test, test.getActivity(), v); } - + /** * Scroll a ViewGroup to the top by repeatedly calling * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)} - * + * * @param test The test case that is being run * @param activity The activity that is in the foreground of the test case * @param v The ViewGroup that should be dragged @@ -162,10 +168,10 @@ public class TouchUtils { next = new ViewStateSnapshot(v); } while (!prev.equals(next)); } - + /** * Simulate touching the center of a view and dragging to the bottom of the screen. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @@ -177,10 +183,10 @@ public class TouchUtils { public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) { dragViewToBottom(test, test.getActivity(), v, 4); } - + /** * Simulate touching the center of a view and dragging to the bottom of the screen. - * + * * @param test The test case that is being run * @param activity The activity that is in the foreground of the test case * @param v The view that should be dragged @@ -188,10 +194,10 @@ public class TouchUtils { public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) { dragViewToBottom(test, activity, v, 4); } - + /** * Simulate touching the center of a view and dragging to the bottom of the screen. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param stepCount How many move steps to include in the drag @@ -205,10 +211,10 @@ public class TouchUtils { int stepCount) { dragViewToBottom(test, test.getActivity(), v, stepCount); } - + /** * Simulate touching the center of a view and dragging to the bottom of the screen. - * + * * @param test The test case that is being run * @param activity The activity that is in the foreground of the test case * @param v The view that should be dragged @@ -220,38 +226,38 @@ public class TouchUtils { int[] xy = new int[2]; v.getLocationOnScreen(xy); - + final int viewWidth = v.getWidth(); final int viewHeight = v.getHeight(); - + final float x = xy[0] + (viewWidth / 2.0f); float fromY = xy[1] + (viewHeight / 2.0f); float toY = screenHeight - 1; - + drag(test, x, x, fromY, toY, stepCount); } /** * Simulate touching the center of a view and releasing quickly (before the tap timeout). - * + * * @param test The test case that is being run * @param v The view that should be clicked */ public static void tapView(InstrumentationTestCase test, View v) { int[] xy = new int[2]; v.getLocationOnScreen(xy); - + final int viewWidth = v.getWidth(); final int viewHeight = v.getHeight(); - + final float x = xy[0] + (viewWidth / 2.0f); float y = xy[1] + (viewHeight / 2.0f); - + Instrumentation inst = test.getInstrumentation(); long downTime = SystemClock.uptimeMillis(); long eventTime = SystemClock.uptimeMillis(); - + MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0); inst.sendPointerSync(event); @@ -308,30 +314,30 @@ public class TouchUtils { /** * Simulate touching the center of a view and releasing. - * + * * @param test The test case that is being run * @param v The view that should be clicked */ public static void clickView(InstrumentationTestCase test, View v) { int[] xy = new int[2]; v.getLocationOnScreen(xy); - + final int viewWidth = v.getWidth(); final int viewHeight = v.getHeight(); - + final float x = xy[0] + (viewWidth / 2.0f); float y = xy[1] + (viewHeight / 2.0f); - + Instrumentation inst = test.getInstrumentation(); long downTime = SystemClock.uptimeMillis(); long eventTime = SystemClock.uptimeMillis(); - + MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0); inst.sendPointerSync(event); inst.waitForIdleSync(); - + eventTime = SystemClock.uptimeMillis(); final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); @@ -344,7 +350,7 @@ public class TouchUtils { event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); inst.sendPointerSync(event); inst.waitForIdleSync(); - + try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -354,7 +360,7 @@ public class TouchUtils { /** * Simulate touching the center of a view, holding until it is a long press, and then releasing. - * + * * @param test The test case that is being run * @param v The view that should be clicked * @@ -369,20 +375,20 @@ public class TouchUtils { /** * Simulate touching the center of a view, holding until it is a long press, and then releasing. - * + * * @param test The test case that is being run * @param v The view that should be clicked */ public static void longClickView(InstrumentationTestCase test, View v) { int[] xy = new int[2]; v.getLocationOnScreen(xy); - + final int viewWidth = v.getWidth(); final int viewHeight = v.getHeight(); - + final float x = xy[0] + (viewWidth / 2.0f); float y = xy[1] + (viewHeight / 2.0f); - + Instrumentation inst = test.getInstrumentation(); long downTime = SystemClock.uptimeMillis(); @@ -399,7 +405,7 @@ public class TouchUtils { x + touchSlop / 2, y + touchSlop / 2, 0); inst.sendPointerSync(event); inst.waitForIdleSync(); - + try { Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f)); } catch (InterruptedException e) { @@ -414,7 +420,7 @@ public class TouchUtils { /** * Simulate touching the center of a view and dragging to the top of the screen. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @@ -426,10 +432,10 @@ public class TouchUtils { public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) { dragViewToTop((InstrumentationTestCase) test, v, 4); } - + /** * Simulate touching the center of a view and dragging to the top of the screen. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param stepCount How many move steps to include in the drag @@ -442,20 +448,20 @@ public class TouchUtils { public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) { dragViewToTop((InstrumentationTestCase) test, v, stepCount); } - + /** * Simulate touching the center of a view and dragging to the top of the screen. - * + * * @param test The test case that is being run * @param v The view that should be dragged */ public static void dragViewToTop(InstrumentationTestCase test, View v) { dragViewToTop(test, v, 4); } - + /** * Simulate touching the center of a view and dragging to the top of the screen. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param stepCount How many move steps to include in the drag @@ -463,21 +469,21 @@ public class TouchUtils { public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) { int[] xy = new int[2]; v.getLocationOnScreen(xy); - + final int viewWidth = v.getWidth(); final int viewHeight = v.getHeight(); - + final float x = xy[0] + (viewWidth / 2.0f); float fromY = xy[1] + (viewHeight / 2.0f); float toY = 0; - + drag(test, x, x, fromY, toY, stepCount); } - + /** * Get the location of a view. Use the gravity param to specify which part of the view to * return. - * + * * @param v View to find * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, * RIGHT) @@ -488,7 +494,7 @@ public class TouchUtils { final int viewWidth = v.getWidth(); final int viewHeight = v.getHeight(); - + switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { case Gravity.TOP: break; @@ -501,7 +507,7 @@ public class TouchUtils { default: // Same as top -- do nothing } - + switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: break; @@ -518,14 +524,14 @@ public class TouchUtils { /** * Simulate touching a view and dragging it by the specified amount. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param deltaX Amount to drag horizontally in pixels * @param deltaY Amount to drag vertically in pixels - * + * * @return distance in pixels covered by the drag * * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of @@ -537,17 +543,17 @@ public class TouchUtils { int deltaX, int deltaY) { return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY); } - + /** * Simulate touching a view and dragging it by the specified amount. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param deltaX Amount to drag horizontally in pixels * @param deltaY Amount to drag vertically in pixels - * + * * @return distance in pixels covered by the drag * * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of @@ -558,29 +564,29 @@ public class TouchUtils { public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX, int deltaY) { int[] xy = new int[2]; - + getStartLocation(v, gravity, xy); final int fromX = xy[0]; final int fromY = xy[1]; - + int distance = (int) Math.hypot(deltaX, deltaY); drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance); return distance; } - + /** * Simulate touching a view and dragging it to a specified location. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param toX Final location of the view after dragging * @param toY Final location of the view after dragging - * + * * @return distance in pixels covered by the drag * * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of @@ -595,14 +601,14 @@ public class TouchUtils { /** * Simulate touching a view and dragging it to a specified location. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param toX Final location of the view after dragging * @param toY Final location of the view after dragging - * + * * @return distance in pixels covered by the drag */ public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX, @@ -610,28 +616,28 @@ public class TouchUtils { int[] xy = new int[2]; getStartLocation(v, gravity, xy); - + final int fromX = xy[0]; final int fromY = xy[1]; - + int deltaX = fromX - toX; int deltaY = fromY - toY; - + int distance = (int)Math.hypot(deltaX, deltaY); drag(test, fromX, toX, fromY, toY, distance); - + return distance; } /** * Simulate touching a view and dragging it to a specified location. Only moves horizontally. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param toX Final location of the view after dragging - * + * * @return distance in pixels covered by the drag * * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of @@ -646,39 +652,39 @@ public class TouchUtils { /** * Simulate touching a view and dragging it to a specified location. Only moves horizontally. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param toX Final location of the view after dragging - * + * * @return distance in pixels covered by the drag */ public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) { int[] xy = new int[2]; getStartLocation(v, gravity, xy); - + final int fromX = xy[0]; final int fromY = xy[1]; - + int deltaX = fromX - toX; drag(test, fromX, toX, fromY, fromY, deltaX); - + return deltaX; } - + /** * Simulate touching a view and dragging it to a specified location. Only moves vertically. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param toY Final location of the view after dragging - * + * * @return distance in pixels covered by the drag * * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of @@ -690,37 +696,37 @@ public class TouchUtils { int toY) { return dragViewToY((InstrumentationTestCase) test, v, gravity, toY); } - + /** * Simulate touching a view and dragging it to a specified location. Only moves vertically. - * + * * @param test The test case that is being run * @param v The view that should be dragged * @param gravity Which part of the view to use for the initial down event. A combination of * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT) * @param toY Final location of the view after dragging - * + * * @return distance in pixels covered by the drag */ public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) { int[] xy = new int[2]; getStartLocation(v, gravity, xy); - + final int fromX = xy[0]; final int fromY = xy[1]; - + int deltaY = fromY - toY; drag(test, fromX, fromX, fromY, toY, deltaY); - + return deltaY; } - + /** * Simulate touching a specific location and dragging to a new location. - * + * * @param test The test case that is being run * @param fromX X coordinate of the initial touch, in screen coordinates * @param toX Xcoordinate of the drag destination, in screen coordinates @@ -737,10 +743,10 @@ public class TouchUtils { float fromY, float toY, int stepCount) { drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount); } - + /** * Simulate touching a specific location and dragging to a new location. - * + * * @param test The test case that is being run * @param fromX X coordinate of the initial touch, in screen coordinates * @param toX Xcoordinate of the drag destination, in screen coordinates @@ -757,7 +763,7 @@ public class TouchUtils { float y = fromY; float x = fromX; - + float yStep = (toY - fromY) / stepCount; float xStep = (toX - fromX) / stepCount; diff --git a/test-runner/src/android/test/ViewAsserts.java b/test-runner/src/android/test/ViewAsserts.java index c575fc5982bf..00ab44379994 100644 --- a/test-runner/src/android/test/ViewAsserts.java +++ b/test-runner/src/android/test/ViewAsserts.java @@ -23,7 +23,15 @@ import android.view.ViewGroup; /** * Some useful assertions about views. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">Espresso + * View Matchers</a> instead. New test should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. + * For more information about UI testing, take the + * <a href="{@docRoot}tools/testing-support-library/index.html">Espresso UI testing</a> training. */ +@Deprecated public class ViewAsserts { private ViewAsserts() {} diff --git a/test-runner/src/android/test/mock/MockApplication.java b/test-runner/src/android/test/mock/MockApplication.java index 572dfbf2b5e6..3257ecf11066 100644 --- a/test-runner/src/android/test/mock/MockApplication.java +++ b/test-runner/src/android/test/mock/MockApplication.java @@ -20,12 +20,17 @@ import android.app.Application; import android.content.res.Configuration; /** - * A mock {@link android.app.Application} class. All methods are non-functional and throw - * {@link java.lang.UnsupportedOperationException}. Override it as necessary to provide the + * A mock {@link android.app.Application} class. All methods are non-functional and throw + * {@link java.lang.UnsupportedOperationException}. Override it as necessary to provide the * operations that you need. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockApplication extends Application { - + public MockApplication() { } @@ -38,7 +43,7 @@ public class MockApplication extends Application { public void onTerminate() { throw new UnsupportedOperationException(); } - + @Override public void onConfigurationChanged(Configuration newConfig) { throw new UnsupportedOperationException(); diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java index 5ef71df341bf..3743fb0811f8 100644 --- a/test-runner/src/android/test/mock/MockContentProvider.java +++ b/test-runner/src/android/test/mock/MockContentProvider.java @@ -41,7 +41,12 @@ import java.util.ArrayList; * Mock implementation of ContentProvider. All methods are non-functional and throw * {@link java.lang.UnsupportedOperationException}. Tests can extend this class to * implement behavior needed for tests. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockContentProvider extends ContentProvider { /* * Note: if you add methods to ContentProvider, you must add similar methods to diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java index aec6c772f3a5..75c8335b6653 100644 --- a/test-runner/src/android/test/mock/MockContentResolver.java +++ b/test-runner/src/android/test/mock/MockContentResolver.java @@ -49,8 +49,12 @@ import java.util.Map; * <p>For more information about application testing, read the * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p> * </div> + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ - +@Deprecated public class MockContentResolver extends ContentResolver { Map<String, ContentProvider> mProviders; diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 64d29787f75f..9b93bda56ea5 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -52,10 +52,15 @@ import java.io.IOException; import java.io.InputStream; /** - * A mock {@link android.content.Context} class. All methods are non-functional and throw + * A mock {@link android.content.Context} class. All methods are non-functional and throw * {@link java.lang.UnsupportedOperationException}. You can use this to inject other dependencies, * mocks, or monitors into the classes you are testing. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockContext extends Context { @Override @@ -82,12 +87,12 @@ public class MockContext extends Context { public Looper getMainLooper() { throw new UnsupportedOperationException(); } - + @Override public Context getApplicationContext() { throw new UnsupportedOperationException(); } - + @Override public void setTheme(int resid) { throw new UnsupportedOperationException(); @@ -124,7 +129,7 @@ public class MockContext extends Context { public ApplicationInfo getApplicationInfo() { throw new UnsupportedOperationException(); } - + @Override public String getPackageResourcePath() { throw new UnsupportedOperationException(); @@ -194,7 +199,7 @@ public class MockContext extends Context { public File getObbDir() { throw new UnsupportedOperationException(); } - + @Override public File getCacheDir() { throw new UnsupportedOperationException(); @@ -216,7 +221,7 @@ public class MockContext extends Context { } @Override - public SQLiteDatabase openOrCreateDatabase(String file, int mode, + public SQLiteDatabase openOrCreateDatabase(String file, int mode, SQLiteDatabase.CursorFactory factory) { throw new UnsupportedOperationException(); } @@ -310,7 +315,7 @@ public class MockContext extends Context { Bundle options) throws IntentSender.SendIntentException { startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags); } - + @Override public void sendBroadcast(Intent intent) { throw new UnsupportedOperationException(); diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java index 28fa0f8041ac..576f24ad6384 100644 --- a/test-runner/src/android/test/mock/MockCursor.java +++ b/test-runner/src/android/test/mock/MockCursor.java @@ -25,15 +25,18 @@ import android.net.Uri; import android.os.Bundle; /** - * <P> * A mock {@link android.database.Cursor} class that isolates the test code from real * Cursor implementation. - * </P> - * <P> + * + * <p> * All methods including ones related to querying the state of the cursor are * are non-functional and throw {@link java.lang.UnsupportedOperationException}. - * </P> + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockCursor implements Cursor { @Override public int getColumnCount() { diff --git a/test-runner/src/android/test/mock/MockDialogInterface.java b/test-runner/src/android/test/mock/MockDialogInterface.java index e4dd0ba2a2d3..d0a5a097918d 100644 --- a/test-runner/src/android/test/mock/MockDialogInterface.java +++ b/test-runner/src/android/test/mock/MockDialogInterface.java @@ -1,14 +1,33 @@ -// Copyright 2008 The Android Open Source Project +/* + * Copyright (C) 2008 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.test.mock; import android.content.DialogInterface; /** - * A mock {@link android.content.DialogInterface} class. All methods are non-functional and throw - * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you + * A mock {@link android.content.DialogInterface} class. All methods are non-functional and throw + * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you * need. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockDialogInterface implements DialogInterface { public void cancel() { throw new UnsupportedOperationException("not implemented yet"); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 5296d4d77657..ffb73f63230c 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -60,7 +60,12 @@ import java.util.List; * A mock {@link android.content.pm.PackageManager} class. All methods are non-functional and throw * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you * need. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockPackageManager extends PackageManager { @Override diff --git a/test-runner/src/android/test/mock/MockResources.java b/test-runner/src/android/test/mock/MockResources.java index 18752cebde1e..880343e5e780 100644 --- a/test-runner/src/android/test/mock/MockResources.java +++ b/test-runner/src/android/test/mock/MockResources.java @@ -32,10 +32,15 @@ import android.graphics.Movie; import java.io.InputStream; /** - * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw - * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you + * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw + * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you * need. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ +@Deprecated public class MockResources extends Resources { public MockResources() { 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 000000000000..0e2467fa9d95 --- /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 000000000000..7e6c8cea409a --- /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 000000000000..9f08fe83015e --- /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 index b1ed85025040..b1ed85025040 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml +++ b/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 a7da286ac6ab..717214740698 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 @@ public class VectorDrawablePerformance extends Activity { 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 ff3d29f41545..ec9e4628d609 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -43,7 +43,8 @@ interface IWifiNanManager 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 773f83bc70dc..50c34d946918 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl @@ -32,7 +32,7 @@ oneway interface IWifiNanSessionListener 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 877f9937bbb9..cb82268ec195 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanManager.java +++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java @@ -319,13 +319,14 @@ public class WifiNanManager { /** * {@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 c6b384e3ae00..d0a94109d0d8 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java @@ -103,8 +103,11 @@ public class WifiNanSession { * @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 c9d08c7610f3..d5e59f0edaf5 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java @@ -210,10 +210,10 @@ public class WifiNanSessionListener { 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 @@ public class WifiNanSessionListener { * {@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 @@ public class WifiNanSessionListener { * @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 @@ public class WifiNanSessionListener { } @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); } |