diff options
118 files changed, 3791 insertions, 1030 deletions
diff --git a/apct-tests/perftests/core/res/layout/twelve_key_entry.xml b/apct-tests/perftests/core/res/layout/twelve_key_entry.xml new file mode 100644 index 000000000000..4d68018d19e3 --- /dev/null +++ b/apct-tests/perftests/core/res/layout/twelve_key_entry.xml @@ -0,0 +1,182 @@ +<?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. +*/ +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="64dip" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:orientation="horizontal"> + + <Button android:id="@+id/one" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/two" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/three" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="64dip" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:orientation="horizontal"> + + <Button android:id="@+id/four" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/five" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/six" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="64dip" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:orientation="horizontal"> + + <Button android:id="@+id/seven" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/eight" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/nine" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="64dip" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:orientation="horizontal"> + + <Button android:id="@+id/cancel" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:text="@android:string/cancel" + /> + + <Button android:id="@+id/zero" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textStyle="bold" + /> + + <Button android:id="@+id/ok" + android:layout_width="0sp" + android:layout_height="fill_parent" + android:layout_weight="1" + android:layout_marginStart="2dip" + android:layout_marginEnd="2dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:text="@android:string/ok" + /> + + </LinearLayout> + +</LinearLayout> diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java index 5503ca94134e..990be24bc805 100644 --- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java +++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java @@ -44,4 +44,15 @@ public class ViewPerfTest { inflater.inflate(R.layout.test_simple_view, root, false); } } + + @Test + public void testTwelveKeyInflate() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + LayoutInflater inflater = LayoutInflater.from(context); + FrameLayout root = new FrameLayout(context); + while (state.keepRunning()) { + inflater.inflate(R.layout.twelve_key_entry, root, false); + } + } } diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java index fd393e9d070c..bb9dc4ae562e 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java @@ -63,7 +63,7 @@ public final class BenchmarkState { // TODO: Tune these values. private static final long TARGET_TEST_DURATION_NS = ms2ns(500); // target testing for 500 ms private static final int MAX_TEST_ITERATIONS = 1000000; - private static final int MIN_TEST_ITERATIONS = 100; + private static final int MIN_TEST_ITERATIONS = 10; private static final int REPEAT_COUNT = 5; private long mStartTimeNs = 0; // Previously captured System.nanoTime(). diff --git a/api/current.txt b/api/current.txt index f5859012ce6c..25741b3e79e6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4658,7 +4658,7 @@ package android.app { method public abstract java.lang.String getName(); } - public abstract class FragmentManager.FragmentLifecycleCallbacks { + public static abstract class FragmentManager.FragmentLifecycleCallbacks { ctor public FragmentManager.FragmentLifecycleCallbacks(); method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle); method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context); @@ -5352,12 +5352,12 @@ package android.app { method public int getImportance(); method public int getLockscreenVisibility(); method public java.lang.CharSequence getName(); - method public android.net.Uri getRingtone(); + method public android.net.Uri getSound(); method public void setBypassDnd(boolean); method public void setImportance(int); method public void setLights(boolean); method public void setLockscreenVisibility(int); - method public void setRingtone(android.net.Uri); + method public void setSound(android.net.Uri); method public void setVibration(boolean); method public boolean shouldShowLights(); method public boolean shouldVibrate(); @@ -63357,7 +63357,10 @@ package java.util.zip { method public java.lang.String getComment(); method public long getCompressedSize(); method public long getCrc(); + method public java.nio.file.attribute.FileTime getCreationTime(); method public byte[] getExtra(); + method public java.nio.file.attribute.FileTime getLastAccessTime(); + method public java.nio.file.attribute.FileTime getLastModifiedTime(); method public int getMethod(); method public java.lang.String getName(); method public long getSize(); @@ -63366,7 +63369,10 @@ package java.util.zip { method public void setComment(java.lang.String); method public void setCompressedSize(long); method public void setCrc(long); + method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime); method public void setExtra(byte[]); + method public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime); + method public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime); method public void setMethod(int); method public void setSize(long); method public void setTime(long); @@ -63437,6 +63443,7 @@ package java.util.zip { method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException; method public java.lang.String getName(); method public int size(); + method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream(); field public static final int CENATT = 36; // 0x24 field public static final int CENATX = 38; // 0x26 field public static final int CENCOM = 32; // 0x20 diff --git a/api/system-current.txt b/api/system-current.txt index 0314b544c6cc..e75bd641cf96 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4556,7 +4556,7 @@ package android.app { method public final void attachBaseContext(android.content.Context); method public final android.os.IBinder onBind(android.content.Intent); method public abstract deprecated java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], int); - method public java.util.List<android.content.pm.EphemeralResolveInfo> onGetEphemeralIntentFilter(int[]); + method public android.content.pm.EphemeralResolveInfo onGetEphemeralIntentFilter(java.lang.String); method public java.util.List<android.content.pm.EphemeralResolveInfo> onGetEphemeralResolveInfo(int[]); field public static final java.lang.String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO"; field public static final java.lang.String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE"; @@ -4811,7 +4811,7 @@ package android.app { method public abstract java.lang.String getName(); } - public abstract class FragmentManager.FragmentLifecycleCallbacks { + public static abstract class FragmentManager.FragmentLifecycleCallbacks { ctor public FragmentManager.FragmentLifecycleCallbacks(); method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle); method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context); @@ -5507,7 +5507,7 @@ package android.app { method public int getImportance(); method public int getLockscreenVisibility(); method public java.lang.CharSequence getName(); - method public android.net.Uri getRingtone(); + method public android.net.Uri getSound(); method public int getUserLockedFields(); method public void lockFields(int); method public void populateFromXml(org.xmlpull.v1.XmlPullParser); @@ -5515,7 +5515,7 @@ package android.app { method public void setImportance(int); method public void setLights(boolean); method public void setLockscreenVisibility(int); - method public void setRingtone(android.net.Uri); + method public void setSound(android.net.Uri); method public void setVibration(boolean); method public boolean shouldShowLights(); method public boolean shouldVibrate(); @@ -5527,7 +5527,7 @@ package android.app { field public static final int USER_LOCKED_IMPORTANCE = 4; // 0x4 field public static final int USER_LOCKED_LIGHTS = 8; // 0x8 field public static final int USER_LOCKED_PRIORITY = 1; // 0x1 - field public static final int USER_LOCKED_RINGTONE = 32; // 0x20 + field public static final int USER_LOCKED_SOUND = 32; // 0x20 field public static final int USER_LOCKED_VIBRATION = 16; // 0x10 field public static final int USER_LOCKED_VISIBILITY = 2; // 0x2 } @@ -66883,7 +66883,10 @@ package java.util.zip { method public java.lang.String getComment(); method public long getCompressedSize(); method public long getCrc(); + method public java.nio.file.attribute.FileTime getCreationTime(); method public byte[] getExtra(); + method public java.nio.file.attribute.FileTime getLastAccessTime(); + method public java.nio.file.attribute.FileTime getLastModifiedTime(); method public int getMethod(); method public java.lang.String getName(); method public long getSize(); @@ -66892,7 +66895,10 @@ package java.util.zip { method public void setComment(java.lang.String); method public void setCompressedSize(long); method public void setCrc(long); + method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime); method public void setExtra(byte[]); + method public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime); + method public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime); method public void setMethod(int); method public void setSize(long); method public void setTime(long); @@ -66963,6 +66969,7 @@ package java.util.zip { method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException; method public java.lang.String getName(); method public int size(); + method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream(); field public static final int CENATT = 36; // 0x24 field public static final int CENATX = 38; // 0x26 field public static final int CENCOM = 32; // 0x20 diff --git a/api/test-current.txt b/api/test-current.txt index 092affc5d51f..4a54733c4f74 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4668,7 +4668,7 @@ package android.app { method public abstract java.lang.String getName(); } - public abstract class FragmentManager.FragmentLifecycleCallbacks { + public static abstract class FragmentManager.FragmentLifecycleCallbacks { ctor public FragmentManager.FragmentLifecycleCallbacks(); method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle); method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context); @@ -5362,12 +5362,12 @@ package android.app { method public int getImportance(); method public int getLockscreenVisibility(); method public java.lang.CharSequence getName(); - method public android.net.Uri getRingtone(); + method public android.net.Uri getSound(); method public void setBypassDnd(boolean); method public void setImportance(int); method public void setLights(boolean); method public void setLockscreenVisibility(int); - method public void setRingtone(android.net.Uri); + method public void setSound(android.net.Uri); method public void setVibration(boolean); method public boolean shouldShowLights(); method public boolean shouldVibrate(); @@ -63618,7 +63618,10 @@ package java.util.zip { method public java.lang.String getComment(); method public long getCompressedSize(); method public long getCrc(); + method public java.nio.file.attribute.FileTime getCreationTime(); method public byte[] getExtra(); + method public java.nio.file.attribute.FileTime getLastAccessTime(); + method public java.nio.file.attribute.FileTime getLastModifiedTime(); method public int getMethod(); method public java.lang.String getName(); method public long getSize(); @@ -63627,7 +63630,10 @@ package java.util.zip { method public void setComment(java.lang.String); method public void setCompressedSize(long); method public void setCrc(long); + method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime); method public void setExtra(byte[]); + method public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime); + method public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime); method public void setMethod(int); method public void setSize(long); method public void setTime(long); @@ -63698,6 +63704,7 @@ package java.util.zip { method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException; method public java.lang.String getName(); method public int size(); + method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream(); field public static final int CENATT = 36; // 0x24 field public static final int CENATX = 38; // 0x26 field public static final int CENCOM = 32; // 0x20 diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 3b3e0704606e..b199984740f2 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -698,7 +698,13 @@ public class ApplicationPackageManager extends PackageManager { @SuppressWarnings("unchecked") @Override public List<ApplicationInfo> getInstalledApplications(int flags) { - final int userId = mContext.getUserId(); + return getInstalledApplicationsAsUser(flags, mContext.getUserId()); + } + + /** @hide */ + @SuppressWarnings("unchecked") + @Override + public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) { try { ParceledListSlice<ApplicationInfo> parceledList = mPM.getInstalledApplications(flags, userId); diff --git a/core/java/android/app/EphemeralResolverService.java b/core/java/android/app/EphemeralResolverService.java index d8d73404f2ae..7e3f626711bf 100644 --- a/core/java/android/app/EphemeralResolverService.java +++ b/core/java/android/app/EphemeralResolverService.java @@ -68,9 +68,9 @@ public abstract class EphemeralResolverService extends Service { /** * Called to retrieve intent filters for ephemeral applications. * - * @param digestPrefix The hash prefix of the ephemeral's domain. + * @param hostName The name of the host to get intent filters for. */ - public List<EphemeralResolveInfo> onGetEphemeralIntentFilter(int digestPrefix[]) { + public EphemeralResolveInfo onGetEphemeralIntentFilter(String hostName) { throw new IllegalStateException("Must define"); } @@ -96,11 +96,11 @@ public abstract class EphemeralResolverService extends Service { @Override public void getEphemeralIntentFilterList( - IRemoteCallback callback, int digestPrefix[], int sequence) { + IRemoteCallback callback, String hostName, int sequence) { final Message msg = mHandler.obtainMessage( ServiceHandler.MSG_GET_EPHEMERAL_INTENT_FILTER, sequence, 0, callback); final Bundle data = new Bundle(); - data.putIntArray(EXTRA_PREFIX, digestPrefix); + data.putString(EXTRA_HOSTNAME, hostName); msg.setData(data); msg.sendToTarget(); } @@ -136,12 +136,11 @@ public abstract class EphemeralResolverService extends Service { case MSG_GET_EPHEMERAL_INTENT_FILTER: { final IRemoteCallback callback = (IRemoteCallback) message.obj; - final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX); - final List<EphemeralResolveInfo> resolveInfo = - onGetEphemeralIntentFilter(digestPrefix); + final String hostName = message.getData().getString(EXTRA_HOSTNAME); + final EphemeralResolveInfo resolveInfo = onGetEphemeralIntentFilter(hostName); final Bundle data = new Bundle(); data.putInt(EXTRA_SEQUENCE, message.arg1); - data.putParcelableList(EXTRA_RESOLVE_INFO, resolveInfo); + data.putParcelable(EXTRA_RESOLVE_INFO, resolveInfo); try { callback.sendResult(data); } catch (RemoteException e) { diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index c7d6a4843f60..9ea3f83992cb 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -387,7 +387,7 @@ public abstract class FragmentManager { * Callback interface for listening to fragment state changes that happen * within a given FragmentManager. */ - public abstract class FragmentLifecycleCallbacks { + public abstract static class FragmentLifecycleCallbacks { /** * Called right before the fragment's {@link Fragment#onAttach(Context)} method is called. * This is a good time to inject any required dependencies for the fragment before any of diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index d63d37be9f2d..82be7abeb87d 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -75,73 +75,78 @@ import java.util.List; * {@hide} */ interface IActivityManager { - // Please keep these transaction codes the same -- they are also - // sent by C++ code. when a new method is added, use the next available transaction id. + // WARNING: when these transactions are updated, check if they are any callers on the native + // side. If so, make sure they are using the correct transaction ids. + // If a transaction which will also be used on the native side is being inserted, add it to + // below block of transactions. + + // =============== Beginning of transactions used on native side as well ====================== + ParcelFileDescriptor openContentUri(in String uriString); + // =============== End of transactions used on native side as well ============================ // Special low-level communication with activity manager. void handleApplicationCrash(in IBinder app, - in ApplicationErrorReport.ParcelableCrashInfo crashInfo) = 1; + in ApplicationErrorReport.ParcelableCrashInfo crashInfo); int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, - int flags, in ProfilerInfo profilerInfo, in Bundle options) = 2; - void unhandledBack() = 3; - ParcelFileDescriptor openContentUri(in String uriString) = 4; + int flags, in ProfilerInfo profilerInfo, in Bundle options); + void unhandledBack(); - boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask) = 10; + boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask); Intent registerReceiver(in IApplicationThread caller, in String callerPackage, in IIntentReceiver receiver, in IntentFilter filter, - in String requiredPermission, int userId) = 11; - void unregisterReceiver(in IIntentReceiver receiver) = 12; + in String requiredPermission, int userId); + void unregisterReceiver(in IIntentReceiver receiver); int broadcastIntent(in IApplicationThread caller, in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode, in String resultData, in Bundle map, in String[] requiredPermissions, - int appOp, in Bundle options, boolean serialized, boolean sticky, int userId) = 13; - void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId) = 14; + int appOp, in Bundle options, boolean serialized, boolean sticky, int userId); + void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId); oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map, - boolean abortBroadcast, int flags) = 15; - void attachApplication(in IApplicationThread app) = 16; + boolean abortBroadcast, int flags); + void attachApplication(in IApplicationThread app); oneway void activityIdle(in IBinder token, in Configuration config, - in boolean stopProfiling) = 17; - void activityPaused(in IBinder token) = 18; + in boolean stopProfiling); + void activityPaused(in IBinder token); oneway void activityStopped(in IBinder token, in Bundle state, - in PersistableBundle persistentState, in CharSequence description) = 19; - String getCallingPackage(in IBinder token) = 20; - ComponentName getCallingActivity(in IBinder token) = 21; - List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, int flags) = 22; - void moveTaskToFront(int task, int flags, in Bundle options) = 23; - void moveTaskBackwards(int task) = 25; - int getTaskForActivity(in IBinder token, in boolean onlyRoot) = 26; + in PersistableBundle persistentState, in CharSequence description); + String getCallingPackage(in IBinder token); + ComponentName getCallingActivity(in IBinder token); + List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, int flags); + void moveTaskToFront(int task, int flags, in Bundle options); + void moveTaskBackwards(int task); + int getTaskForActivity(in IBinder token, in boolean onlyRoot); ContentProviderHolder getContentProvider(in IApplicationThread caller, - in String name, int userId, boolean stable) = 28; + in String name, int userId, boolean stable); void publishContentProviders(in IApplicationThread caller, - in List<ContentProviderHolder> providers) = 29; - boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta) = 30; - void finishSubActivity(in IBinder token, in String resultWho, int requestCode) = 31; - PendingIntent getRunningServiceControlPanel(in ComponentName service) = 32; + in List<ContentProviderHolder> providers); + boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta); + void finishSubActivity(in IBinder token, in String resultWho, int requestCode); + PendingIntent getRunningServiceControlPanel(in ComponentName service); ComponentName startService(in IApplicationThread caller, in Intent service, - in String resolvedType, in String callingPackage, int userId) = 33; + in String resolvedType, in String callingPackage, int userId); int stopService(in IApplicationThread caller, in Intent service, - in String resolvedType, int userId) = 34; + in String resolvedType, int userId); int bindService(in IApplicationThread caller, in IBinder token, in Intent service, in String resolvedType, in IServiceConnection connection, int flags, - in String callingPackage, int userId) = 35; - boolean unbindService(in IServiceConnection connection) = 36; - void publishService(in IBinder token, in Intent intent, in IBinder service) = 37; - void activityResumed(in IBinder token) = 38; - void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent) = 41; - void setAlwaysFinish(boolean enabled) = 42; + in String callingPackage, int userId); + boolean unbindService(in IServiceConnection connection); + void publishService(in IBinder token, in Intent intent, in IBinder service); + void activityResumed(in IBinder token); + void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent); + void setAlwaysFinish(boolean enabled); boolean startInstrumentation(in ComponentName className, in String profileFile, int flags, in Bundle arguments, in IInstrumentationWatcher watcher, in IUiAutomationConnection connection, int userId, - in String abiOverride) = 43; + in String abiOverride); void finishInstrumentation(in IApplicationThread target, int resultCode, - in Bundle results) = 44; + in Bundle results); /** * @return A copy of global {@link Configuration}, contains general settings for the entire * system. Corresponds to the configuration of the default display. * @throws RemoteException */ - Configuration getConfiguration() = 45; + Configuration getConfiguration(); /** * Updates global configuration and applies changes to the entire system. * @param values Update values for global configuration. If null is passed it will request the @@ -149,183 +154,183 @@ interface IActivityManager { * @throws RemoteException * @return Returns true if the configuration was updated. */ - boolean updateConfiguration(in Configuration values) = 46; - boolean stopServiceToken(in ComponentName className, in IBinder token, int startId) = 47; - ComponentName getActivityClassForToken(in IBinder token) = 48; - String getPackageForToken(in IBinder token) = 49; - void setProcessLimit(int max) = 50; - int getProcessLimit() = 51; - int checkPermission(in String permission, int pid, int uid) = 52; + boolean updateConfiguration(in Configuration values); + boolean stopServiceToken(in ComponentName className, in IBinder token, int startId); + ComponentName getActivityClassForToken(in IBinder token); + String getPackageForToken(in IBinder token); + void setProcessLimit(int max); + int getProcessLimit(); + int checkPermission(in String permission, int pid, int uid); int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId, - in IBinder callerToken) = 53; + in IBinder callerToken); void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri, - int mode, int userId) = 54; - void revokeUriPermission(in IApplicationThread caller, in Uri uri, int mode, int userId) = 55; - void setActivityController(in IActivityController watcher, boolean imAMonkey) = 56; - void showWaitingForDebugger(in IApplicationThread who, boolean waiting) = 57; + int mode, int userId); + void revokeUriPermission(in IApplicationThread caller, in Uri uri, int mode, int userId); + void setActivityController(in IActivityController watcher, boolean imAMonkey); + void showWaitingForDebugger(in IApplicationThread who, boolean waiting); /* * This will deliver the specified signal to all the persistent processes. Currently only * SIGUSR1 is delivered. All others are ignored. */ - void signalPersistentProcesses(int signal) = 58; + void signalPersistentProcesses(int signal); ParceledListSlice getRecentTasks(int maxNum, - int flags, int userId) = 59; - oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res) = 60; - oneway void activityDestroyed(in IBinder token) = 61; + int flags, int userId); + oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res); + oneway void activityDestroyed(in IBinder token); IIntentSender getIntentSender(int type, in String packageName, in IBinder token, in String resultWho, int requestCode, in Intent[] intents, in String[] resolvedTypes, - int flags, in Bundle options, int userId) = 62; - void cancelIntentSender(in IIntentSender sender) = 63; - String getPackageForIntentSender(in IIntentSender sender) = 64; - void enterSafeMode() = 65; + int flags, in Bundle options, int userId); + void cancelIntentSender(in IIntentSender sender); + String getPackageForIntentSender(in IIntentSender sender); + void enterSafeMode(); boolean startNextMatchingActivity(in IBinder callingActivity, - in Intent intent, in Bundle options) = 66; + in Intent intent, in Bundle options); void noteWakeupAlarm(in IIntentSender sender, int sourceUid, - in String sourcePkg, in String tag) = 67; - void removeContentProvider(in IBinder connection, boolean stable) = 68; - void setRequestedOrientation(in IBinder token, int requestedOrientation) = 69; - int getRequestedOrientation(in IBinder token) = 70; - void unbindFinished(in IBinder token, in Intent service, boolean doRebind) = 71; - void setProcessForeground(in IBinder token, int pid, boolean isForeground) = 72; + in String sourcePkg, in String tag); + void removeContentProvider(in IBinder connection, boolean stable); + void setRequestedOrientation(in IBinder token, int requestedOrientation); + int getRequestedOrientation(in IBinder token); + void unbindFinished(in IBinder token, in Intent service, boolean doRebind); + void setProcessForeground(in IBinder token, int pid, boolean isForeground); void setServiceForeground(in ComponentName className, in IBinder token, - int id, in Notification notification, int flags) = 73; - boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot) = 74; - void getMemoryInfo(out ActivityManager.MemoryInfo outInfo) = 75; - List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() = 76; + int id, in Notification notification, int flags); + boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot); + void getMemoryInfo(out ActivityManager.MemoryInfo outInfo); + List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState(); boolean clearApplicationUserData(in String packageName, - in IPackageDataObserver observer, int userId) = 77; - void forceStopPackage(in String packageName, int userId) = 78; - boolean killPids(in int[] pids, in String reason, boolean secure) = 79; - List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags) = 80; - ActivityManager.TaskThumbnail getTaskThumbnail(int taskId) = 81; + in IPackageDataObserver observer, int userId); + void forceStopPackage(in String packageName, int userId); + boolean killPids(in int[] pids, in String reason, boolean secure); + List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags); + ActivityManager.TaskThumbnail getTaskThumbnail(int taskId); // Retrieve running application processes in the system - List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() = 82; + List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); // Get device configuration - ConfigurationInfo getDeviceConfigurationInfo() = 83; - IBinder peekService(in Intent service, in String resolvedType, in String callingPackage) = 84; + ConfigurationInfo getDeviceConfigurationInfo(); + IBinder peekService(in Intent service, in String resolvedType, in String callingPackage); // Turn on/off profiling in a particular process. boolean profileControl(in String process, int userId, boolean start, - in ProfilerInfo profilerInfo, int profileType) = 85; - boolean shutdown(int timeout) = 86; - void stopAppSwitches() = 87; - void resumeAppSwitches() = 88; - boolean bindBackupAgent(in String packageName, int backupRestoreMode, int userId) = 89; - void backupAgentCreated(in String packageName, in IBinder agent) = 90; - void unbindBackupAgent(in ApplicationInfo appInfo) = 91; - int getUidForIntentSender(in IIntentSender sender) = 92; + in ProfilerInfo profilerInfo, int profileType); + boolean shutdown(int timeout); + void stopAppSwitches(); + void resumeAppSwitches(); + boolean bindBackupAgent(in String packageName, int backupRestoreMode, int userId); + void backupAgentCreated(in String packageName, in IBinder agent); + void unbindBackupAgent(in ApplicationInfo appInfo); + int getUidForIntentSender(in IIntentSender sender); int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, - boolean requireFull, in String name, in String callerPackage) = 93; - void addPackageDependency(in String packageName) = 94; - void killApplication(in String pkg, int appId, int userId, in String reason) = 95; - void closeSystemDialogs(in String reason) = 96; - Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids) = 97; - void killApplicationProcess(in String processName, int uid) = 98; + boolean requireFull, in String name, in String callerPackage); + void addPackageDependency(in String packageName); + void killApplication(in String pkg, int appId, int userId, in String reason); + void closeSystemDialogs(in String reason); + Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids); + void killApplicationProcess(in String processName, int uid); int startActivityIntentSender(in IApplicationThread caller, in IntentSender intent, in Intent fillInIntent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, - int flagsMask, int flagsValues, in Bundle options) = 99; + int flagsMask, int flagsValues, in Bundle options); void overridePendingTransition(in IBinder token, in String packageName, - int enterAnim, int exitAnim) = 100; + int enterAnim, int exitAnim); // Special low-level communication with activity manager. boolean handleApplicationWtf(in IBinder app, in String tag, boolean system, - in ApplicationErrorReport.ParcelableCrashInfo crashInfo) = 101; - void killBackgroundProcesses(in String packageName, int userId) = 102; - boolean isUserAMonkey() = 103; + in ApplicationErrorReport.ParcelableCrashInfo crashInfo); + void killBackgroundProcesses(in String packageName, int userId); + boolean isUserAMonkey(); WaitResult startActivityAndWait(in IApplicationThread caller, in String callingPackage, in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options, - int userId) = 104; - boolean willActivityBeVisible(in IBinder token) = 105; + int userId); + boolean willActivityBeVisible(in IBinder token); int startActivityWithConfig(in IApplicationThread caller, in String callingPackage, in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, int startFlags, in Configuration newConfig, - in Bundle options, int userId) = 106; + in Bundle options, int userId); // Retrieve info of applications installed on external media that are currently // running. - List<ApplicationInfo> getRunningExternalApplications() = 107; - void finishHeavyWeightApp() = 108; + List<ApplicationInfo> getRunningExternalApplications(); + void finishHeavyWeightApp(); // A StrictMode violation to be handled. The violationMask is a // subset of the original StrictMode policy bitmask, with only the // bit violated and penalty bits to be executed by the // ActivityManagerService remaining set. void handleApplicationStrictModeViolation(in IBinder app, int violationMask, - in StrictMode.ViolationInfo crashInfo) = 109; - boolean isImmersive(in IBinder token) = 110; - void setImmersive(in IBinder token, boolean immersive) = 111; - boolean isTopActivityImmersive() = 112; - void crashApplication(int uid, int initialPid, in String packageName, in String message) = 113; - String getProviderMimeType(in Uri uri, int userId) = 114; - IBinder newUriPermissionOwner(in String name) = 115; + in StrictMode.ViolationInfo crashInfo); + boolean isImmersive(in IBinder token); + void setImmersive(in IBinder token, boolean immersive); + boolean isTopActivityImmersive(); + void crashApplication(int uid, int initialPid, in String packageName, in String message); + String getProviderMimeType(in Uri uri, int userId); + IBinder newUriPermissionOwner(in String name); void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg, - in Uri uri, int mode, int sourceUserId, int targetUserId) = 116; - void revokeUriPermissionFromOwner(in IBinder owner, in Uri uri, int mode, int userId) = 117; + in Uri uri, int mode, int sourceUserId, int targetUserId); + void revokeUriPermissionFromOwner(in IBinder owner, in Uri uri, int mode, int userId); int checkGrantUriPermission(int callingUid, in String targetPkg, in Uri uri, - int modeFlags, int userId) = 118; + int modeFlags, int userId); // Cause the specified process to dump the specified heap. boolean dumpHeap(in String process, int userId, boolean managed, in String path, - in ParcelFileDescriptor fd) = 119; + in ParcelFileDescriptor fd); int startActivities(in IApplicationThread caller, in String callingPackage, in Intent[] intents, in String[] resolvedTypes, in IBinder resultTo, - in Bundle options, int userId) = 120; - boolean isUserRunning(int userid, int flags) = 121; - oneway void activitySlept(in IBinder token) = 122; - int getFrontActivityScreenCompatMode() = 123; - void setFrontActivityScreenCompatMode(int mode) = 124; - int getPackageScreenCompatMode(in String packageName) = 125; - void setPackageScreenCompatMode(in String packageName, int mode) = 126; - boolean getPackageAskScreenCompat(in String packageName) = 127; - void setPackageAskScreenCompat(in String packageName, boolean ask) = 128; - boolean switchUser(int userid) = 129; - void setFocusedTask(int taskId) = 130; - boolean removeTask(int taskId) = 131; - void registerProcessObserver(in IProcessObserver observer) = 132; - void unregisterProcessObserver(in IProcessObserver observer) = 133; - boolean isIntentSenderTargetedToPackage(in IIntentSender sender) = 134; - void updatePersistentConfiguration(in Configuration values) = 135; - long[] getProcessPss(in int[] pids) = 136; - void showBootMessage(in CharSequence msg, boolean always) = 137; - void killAllBackgroundProcesses() = 139; + in Bundle options, int userId); + boolean isUserRunning(int userid, int flags); + oneway void activitySlept(in IBinder token); + int getFrontActivityScreenCompatMode(); + void setFrontActivityScreenCompatMode(int mode); + int getPackageScreenCompatMode(in String packageName); + void setPackageScreenCompatMode(in String packageName, int mode); + boolean getPackageAskScreenCompat(in String packageName); + void setPackageAskScreenCompat(in String packageName, boolean ask); + boolean switchUser(int userid); + void setFocusedTask(int taskId); + boolean removeTask(int taskId); + void registerProcessObserver(in IProcessObserver observer); + void unregisterProcessObserver(in IProcessObserver observer); + boolean isIntentSenderTargetedToPackage(in IIntentSender sender); + void updatePersistentConfiguration(in Configuration values); + long[] getProcessPss(in int[] pids); + void showBootMessage(in CharSequence msg, boolean always); + void killAllBackgroundProcesses(); ContentProviderHolder getContentProviderExternal(in String name, int userId, - in IBinder token) = 140; - void removeContentProviderExternal(in String name, in IBinder token) = 141; + in IBinder token); + void removeContentProviderExternal(in String name, in IBinder token); // Get memory information about the calling process. - void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo) = 142; - boolean killProcessesBelowForeground(in String reason) = 143; - UserInfo getCurrentUser() = 144; - boolean shouldUpRecreateTask(in IBinder token, in String destAffinity) = 145; + void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo); + boolean killProcessesBelowForeground(in String reason); + UserInfo getCurrentUser(); + boolean shouldUpRecreateTask(in IBinder token, in String destAffinity); boolean navigateUpTo(in IBinder token, in Intent target, int resultCode, - in Intent resultData) = 146; - void setLockScreenShown(boolean showing) = 147; - boolean finishActivityAffinity(in IBinder token) = 148; + in Intent resultData); + void setLockScreenShown(boolean showing); + boolean finishActivityAffinity(in IBinder token); // This is not public because you need to be very careful in how you // manage your activity to make sure it is always the uid you expect. - int getLaunchedFromUid(in IBinder activityToken) = 149; - void unstableProviderDied(in IBinder connection) = 150; - boolean isIntentSenderAnActivity(in IIntentSender sender) = 151; + int getLaunchedFromUid(in IBinder activityToken); + void unstableProviderDied(in IBinder connection); + boolean isIntentSenderAnActivity(in IIntentSender sender); int startActivityAsUser(in IApplicationThread caller, in String callingPackage, in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, int flags, in ProfilerInfo profilerInfo, - in Bundle options, int userId) = 152; - int stopUser(int userid, boolean force, in IStopUserCallback callback) = 153; - void registerUserSwitchObserver(in IUserSwitchObserver observer, in String name) = 154; - void unregisterUserSwitchObserver(in IUserSwitchObserver observer) = 155; - int[] getRunningUserIds() = 156; - void requestBugReport(int bugreportType) = 157; - long inputDispatchingTimedOut(int pid, boolean aboveSystem, in String reason) = 158; - void clearPendingBackup() = 159; - Intent getIntentForIntentSender(in IIntentSender sender) = 160; - Bundle getAssistContextExtras(int requestType) = 161; + in Bundle options, int userId); + int stopUser(int userid, boolean force, in IStopUserCallback callback); + void registerUserSwitchObserver(in IUserSwitchObserver observer, in String name); + void unregisterUserSwitchObserver(in IUserSwitchObserver observer); + int[] getRunningUserIds(); + void requestBugReport(int bugreportType); + long inputDispatchingTimedOut(int pid, boolean aboveSystem, in String reason); + void clearPendingBackup(); + Intent getIntentForIntentSender(in IIntentSender sender); + Bundle getAssistContextExtras(int requestType); void reportAssistContextExtras(in IBinder token, in Bundle extras, - in AssistStructure structure, in AssistContent content, in Uri referrer) = 162; + in AssistStructure structure, in AssistContent content, in Uri referrer); // This is not public because you need to be very careful in how you // manage your activity to make sure it is always the uid you expect. - String getLaunchedFromPackage(in IBinder activityToken) = 163; - void killUid(int appId, int userId, in String reason) = 164; - void setUserIsMonkey(boolean monkey) = 165; - void hang(in IBinder who, boolean allowRestart) = 166; + String getLaunchedFromPackage(in IBinder activityToken); + void killUid(int appId, int userId, in String reason); + void setUserIsMonkey(boolean monkey); + void hang(in IBinder who, boolean allowRestart); IActivityContainer createVirtualActivityContainer(in IBinder parentActivityToken, - in IActivityContainerCallback callback) = 167; - void moveTaskToStack(int taskId, int stackId, boolean toTop) = 168; + in IActivityContainerCallback callback); + void moveTaskToStack(int taskId, int stackId, boolean toTop); /** * Resizes the input stack id to the given bounds. * @@ -341,129 +346,129 @@ interface IActivityManager { * @throws RemoteException */ void resizeStack(int stackId, in Rect bounds, boolean allowResizeInDockedMode, - boolean preserveWindows, boolean animate, int animationDuration) = 169; - List<ActivityManager.StackInfo> getAllStackInfos() = 170; - void setFocusedStack(int stackId) = 171; - ActivityManager.StackInfo getStackInfo(int stackId) = 172; - boolean convertFromTranslucent(in IBinder token) = 173; - boolean convertToTranslucent(in IBinder token, in Bundle options) = 174; - void notifyActivityDrawn(in IBinder token) = 175; - void reportActivityFullyDrawn(in IBinder token) = 176; - void restart() = 177; - void performIdleMaintenance() = 178; - void takePersistableUriPermission(in Uri uri, int modeFlags, int userId) = 179; - void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId) = 180; - ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming) = 181; - void appNotRespondingViaProvider(in IBinder connection) = 182; - Rect getTaskBounds(int taskId) = 183; - int getActivityDisplayId(in IBinder activityToken) = 184; - boolean setProcessMemoryTrimLevel(in String process, int uid, int level) = 186; + boolean preserveWindows, boolean animate, int animationDuration); + List<ActivityManager.StackInfo> getAllStackInfos(); + void setFocusedStack(int stackId); + ActivityManager.StackInfo getStackInfo(int stackId); + boolean convertFromTranslucent(in IBinder token); + boolean convertToTranslucent(in IBinder token, in Bundle options); + void notifyActivityDrawn(in IBinder token); + void reportActivityFullyDrawn(in IBinder token); + void restart(); + void performIdleMaintenance(); + void takePersistableUriPermission(in Uri uri, int modeFlags, int userId); + void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId); + ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming); + void appNotRespondingViaProvider(in IBinder connection); + Rect getTaskBounds(int taskId); + int getActivityDisplayId(in IBinder activityToken); + boolean setProcessMemoryTrimLevel(in String process, int uid, int level); // Start of L transactions - String getTagForIntentSender(in IIntentSender sender, in String prefix) = 210; - boolean startUserInBackground(int userid) = 211; - boolean isInHomeStack(int taskId) = 212; - void startLockTaskModeById(int taskId) = 213; - void startLockTaskModeByToken(in IBinder token) = 214; - void stopLockTaskMode() = 215; - boolean isInLockTaskMode() = 216; - void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values) = 217; + String getTagForIntentSender(in IIntentSender sender, in String prefix); + boolean startUserInBackground(int userid); + boolean isInHomeStack(int taskId); + void startLockTaskModeById(int taskId); + void startLockTaskModeByToken(in IBinder token); + void stopLockTaskMode(); + boolean isInLockTaskMode(); + void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values); int startVoiceActivity(in String callingPackage, int callingPid, int callingUid, in Intent intent, in String resolvedType, in IVoiceInteractionSession session, in IVoiceInteractor interactor, int flags, in ProfilerInfo profilerInfo, - in Bundle options, int userId) = 218; - Bundle getActivityOptions(in IBinder token) = 219; - List<IBinder> getAppTasks(in String callingPackage) = 220; - void startSystemLockTaskMode(int taskId) = 221; - void stopSystemLockTaskMode() = 222; - void finishVoiceTask(in IVoiceInteractionSession session) = 223; - boolean isTopOfTask(in IBinder token) = 224; - boolean requestVisibleBehind(in IBinder token, boolean visible) = 225; - boolean isBackgroundVisibleBehind(in IBinder token) = 226; - void backgroundResourcesReleased(in IBinder token) = 227; - void notifyLaunchTaskBehindComplete(in IBinder token) = 228; - int startActivityFromRecents(int taskId, in Bundle options) = 229; - void notifyEnterAnimationComplete(in IBinder token) = 230; + in Bundle options, int userId); + Bundle getActivityOptions(in IBinder token); + List<IBinder> getAppTasks(in String callingPackage); + void startSystemLockTaskMode(int taskId); + void stopSystemLockTaskMode(); + void finishVoiceTask(in IVoiceInteractionSession session); + boolean isTopOfTask(in IBinder token); + boolean requestVisibleBehind(in IBinder token, boolean visible); + boolean isBackgroundVisibleBehind(in IBinder token); + void backgroundResourcesReleased(in IBinder token); + void notifyLaunchTaskBehindComplete(in IBinder token); + int startActivityFromRecents(int taskId, in Bundle options); + void notifyEnterAnimationComplete(in IBinder token); int startActivityAsCaller(in IApplicationThread caller, in String callingPackage, in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options, - boolean ignoreTargetSecurity, int userId) = 232; + boolean ignoreTargetSecurity, int userId); int addAppTask(in IBinder activityToken, in Intent intent, - in ActivityManager.TaskDescription description, in Bitmap thumbnail) = 233; - Point getAppTaskThumbnailSize() = 234; - boolean releaseActivityInstance(in IBinder token) = 235; - void releaseSomeActivities(in IApplicationThread app) = 236; - void bootAnimationComplete() = 237; - Bitmap getTaskDescriptionIcon(in String filename, int userId) = 238; + in ActivityManager.TaskDescription description, in Bitmap thumbnail); + Point getAppTaskThumbnailSize(); + boolean releaseActivityInstance(in IBinder token); + void releaseSomeActivities(in IApplicationThread app); + void bootAnimationComplete(); + Bitmap getTaskDescriptionIcon(in String filename, int userId); boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle, - in Bundle args) = 239; - void startInPlaceAnimationOnFrontMostApplication(in Bundle opts) = 240; + in Bundle args); + void startInPlaceAnimationOnFrontMostApplication(in Bundle opts); int checkPermissionWithToken(in String permission, int pid, int uid, - in IBinder callerToken) = 241; - void registerTaskStackListener(in ITaskStackListener listener) = 242; + in IBinder callerToken); + void registerTaskStackListener(in ITaskStackListener listener); // Start of M transactions - void notifyCleartextNetwork(int uid, in byte[] firstPacket) = 280; - IActivityContainer createStackOnDisplay(int displayId) = 281; - int getFocusedStackId() = 282; - void setTaskResizeable(int taskId, int resizeableMode) = 283; + void notifyCleartextNetwork(int uid, in byte[] firstPacket); + IActivityContainer createStackOnDisplay(int displayId); + int getFocusedStackId(); + void setTaskResizeable(int taskId, int resizeableMode); boolean requestAssistContextExtras(int requestType, in IResultReceiver receiver, in Bundle receiverExtras, in IBinder activityToken, - boolean focused, boolean newSessionId) = 284; - void resizeTask(int taskId, in Rect bounds, int resizeMode) = 285; - int getLockTaskModeState() = 286; + boolean focused, boolean newSessionId); + void resizeTask(int taskId, in Rect bounds, int resizeMode); + int getLockTaskModeState(); void setDumpHeapDebugLimit(in String processName, int uid, long maxMemSize, - in String reportPackage) = 287; - void dumpHeapFinished(in String path) = 288; - void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake) = 289; - void updateLockTaskPackages(int userId, in String[] packages) = 290; - void noteAlarmStart(in IIntentSender sender, int sourceUid, in String tag) = 291; - void noteAlarmFinish(in IIntentSender sender, int sourceUid, in String tag) = 292; - int getPackageProcessState(in String packageName, in String callingPackage) = 293; - oneway void showLockTaskEscapeMessage(in IBinder token) = 294; - void updateDeviceOwner(in String packageName) = 295; + in String reportPackage); + void dumpHeapFinished(in String path); + void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake); + void updateLockTaskPackages(int userId, in String[] packages); + void noteAlarmStart(in IIntentSender sender, int sourceUid, in String tag); + void noteAlarmFinish(in IIntentSender sender, int sourceUid, in String tag); + int getPackageProcessState(in String packageName, in String callingPackage); + oneway void showLockTaskEscapeMessage(in IBinder token); + void updateDeviceOwner(in String packageName); /** * Notify the system that the keyguard is going away. * * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE} * etc. */ - void keyguardGoingAway(int flags) = 296; + void keyguardGoingAway(int flags); void registerUidObserver(in IUidObserver observer, int which, int cutpoint, - String callingPackage) = 297; - void unregisterUidObserver(in IUidObserver observer) = 298; - boolean isAssistDataAllowedOnCurrentActivity() = 299; - boolean showAssistFromActivity(in IBinder token, in Bundle args) = 300; - boolean isRootVoiceInteraction(in IBinder token) = 301; + String callingPackage); + void unregisterUidObserver(in IUidObserver observer); + boolean isAssistDataAllowedOnCurrentActivity(); + boolean showAssistFromActivity(in IBinder token, in Bundle args); + boolean isRootVoiceInteraction(in IBinder token); // Start of N transactions // Start Binder transaction tracking for all applications. - boolean startBinderTracking() = 340; + boolean startBinderTracking(); // Stop Binder transaction tracking for all applications and dump trace data to the given file // descriptor. - boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd) = 341; - void positionTaskInStack(int taskId, int stackId, int position) = 342; - int getActivityStackId(in IBinder token) = 343; - void exitFreeformMode(in IBinder token) = 344; + boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd); + void positionTaskInStack(int taskId, int stackId, int position); + int getActivityStackId(in IBinder token); + void exitFreeformMode(in IBinder token); void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration, - in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations) = 345; + in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations); boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, - in Rect initialBounds, boolean moveHomeStackFront) = 346; - void suppressResizeConfigChanges(boolean suppress) = 347; - void moveTasksToFullscreenStack(int fromStackId, boolean onTop) = 348; - boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds) = 349; - int getAppStartMode(int uid, in String packageName) = 350; + in Rect initialBounds, boolean moveHomeStackFront); + void suppressResizeConfigChanges(boolean suppress); + void moveTasksToFullscreenStack(int fromStackId, boolean onTop); + boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds); + int getAppStartMode(int uid, in String packageName); boolean unlockUser(int userid, in byte[] token, in byte[] secret, - in IProgressListener listener) = 351; - boolean isInMultiWindowMode(in IBinder token) = 352; - boolean isInPictureInPictureMode(in IBinder token) = 353; - void killPackageDependents(in String packageName, int userId) = 354; - void enterPictureInPictureMode(in IBinder token) = 355; - void activityRelaunched(in IBinder token) = 356; - IBinder getUriPermissionOwnerForActivity(in IBinder activityToken) = 357; + in IProgressListener listener); + boolean isInMultiWindowMode(in IBinder token); + boolean isInPictureInPictureMode(in IBinder token); + void killPackageDependents(in String packageName, int userId); + void enterPictureInPictureMode(in IBinder token); + void activityRelaunched(in IBinder token); + IBinder getUriPermissionOwnerForActivity(in IBinder activityToken); /** * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change. * @@ -485,22 +490,22 @@ interface IActivityManager { */ void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds, in Rect tempDockedTaskInsetBounds, - in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds) = 358; - int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName) = 359; + in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds); + int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName); // Gets the URI permissions granted to an arbitrary package. // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package // granted to another packages (instead of those granted to it). - ParceledListSlice getGrantedUriPermissions(in String packageName, int userId) = 360; + ParceledListSlice getGrantedUriPermissions(in String packageName, int userId); // Clears the URI permissions granted to an arbitrary package. - void clearGrantedUriPermissions(in String packageName, int userId) = 361; - boolean isAppForeground(int uid) = 362; - void startLocalVoiceInteraction(in IBinder token, in Bundle options) = 363; - void stopLocalVoiceInteraction(in IBinder token) = 364; - boolean supportsLocalVoiceInteraction() = 365; - void notifyPinnedStackAnimationEnded() = 366; - void removeStack(int stackId) = 367; - void makePackageIdle(String packageName, int userId) = 368; - int getMemoryTrimLevel() = 369; + void clearGrantedUriPermissions(in String packageName, int userId); + boolean isAppForeground(int uid); + void startLocalVoiceInteraction(in IBinder token, in Bundle options); + void stopLocalVoiceInteraction(in IBinder token); + boolean supportsLocalVoiceInteraction(); + void notifyPinnedStackAnimationEnded(); + void removeStack(int stackId); + void makePackageIdle(String packageName, int userId); + int getMemoryTrimLevel(); /** * Resizes the pinned stack. * @@ -510,24 +515,24 @@ interface IActivityManager { * flexibility while resizing, or {@code null} if they should be the * same as the stack bounds. */ - void resizePinnedStack(in Rect pinnedBounds, in Rect tempPinnedTaskBounds) = 370; - boolean isVrModePackageEnabled(in ComponentName packageName) = 371; + void resizePinnedStack(in Rect pinnedBounds, in Rect tempPinnedTaskBounds); + boolean isVrModePackageEnabled(in ComponentName packageName); /** * Moves all tasks from the docked stack in the fullscreen stack and puts the top task of the * fullscreen stack into the docked stack. */ - void swapDockedAndFullscreenStack() = 372; - void notifyLockedProfile(int userId) = 373; - void startConfirmDeviceCredentialIntent(in Intent intent) = 374; - void sendIdleJobTrigger() = 375; + void swapDockedAndFullscreenStack(); + void notifyLockedProfile(int userId); + void startConfirmDeviceCredentialIntent(in Intent intent); + void sendIdleJobTrigger(); int sendIntentSender(in IIntentSender target, int code, in Intent intent, in String resolvedType, in IIntentReceiver finishedReceiver, - in String requiredPermission, in Bundle options) = 376; + in String requiredPermission, in Bundle options); // Start of N MR1 transactions - void setVrThread(int tid) = 377; - void setRenderThread(int tid) = 378; + void setVrThread(int tid); + void setRenderThread(int tid); /** * Lets activity manager know whether the calling process is currently showing "top-level" UI * that is not an activity, i.e. windows on the screen the user is currently interacting with. @@ -536,7 +541,7 @@ interface IActivityManager { * * @param hasTopUi Whether the calling process has "top-level" UI. */ - void setHasTopUi(boolean hasTopUi) = 379; + void setHasTopUi(boolean hasTopUi); /** * Returns if the target of the PendingIntent can be fired directly, without triggering * a work profile challenge. This can happen if the PendingIntent is to start direct-boot @@ -547,10 +552,10 @@ interface IActivityManager { * otherwise. * @throws RemoteException */ - boolean canBypassWorkChallenge(in PendingIntent intent) = 380; + boolean canBypassWorkChallenge(in PendingIntent intent); // Start of O transactions - void requestActivityRelaunch(in IBinder token) = 400; + void requestActivityRelaunch(in IBinder token); /** * Updates override configuration applied to specific display. * @param values Update values for display configuration. If null is passed it will request the @@ -559,14 +564,16 @@ interface IActivityManager { * @throws RemoteException * @return Returns true if the configuration was updated. */ - boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId) = 401; - void unregisterTaskStackListener(ITaskStackListener listener) = 402; - void moveStackToDisplay(int stackId, int displayId) = 403; - void enterPictureInPictureModeWithAspectRatio(in IBinder token, float aspectRatio) = 404; - void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio) = 405; + boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId); + void unregisterTaskStackListener(ITaskStackListener listener); + void moveStackToDisplay(int stackId, int displayId); + void enterPictureInPictureModeWithAspectRatio(in IBinder token, float aspectRatio); + void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio); boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras, - in IBinder activityToken) = 406; + in IBinder activityToken); - // Please keep these transaction codes the same -- they are also - // sent by C++ code. when a new method is added, use the next available transaction id. -} + // WARNING: when these transactions are updated, check if they are any callers on the native + // side. If so, make sure they are using the correct transaction ids. + // If a transaction which will also be used on the native side is being inserted, add it + // alongside with other transactions of this kind at the top of this file. +}
\ No newline at end of file diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index c2b5b9392628..8c9837b6ed4d 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -51,35 +51,31 @@ import java.util.Map; * {@hide} */ oneway interface IApplicationThread { - /** - * Don't change the existing transaction Ids as they could be used in the native code. - * When adding a new method, assign the next available transaction id. - */ void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, - int configChanges, boolean dontReport) = 0; + int configChanges, boolean dontReport); void scheduleStopActivity(IBinder token, boolean showWindow, - int configChanges) = 2; - void scheduleWindowVisibility(IBinder token, boolean showWindow) = 3; + int configChanges); + void scheduleWindowVisibility(IBinder token, boolean showWindow); void scheduleResumeActivity(IBinder token, int procState, boolean isForward, - in Bundle resumeArgs) = 4; - void scheduleSendResult(IBinder token, in List<ResultInfo> results) = 5; + in Bundle resumeArgs); + void scheduleSendResult(IBinder token, in List<ResultInfo> results); void scheduleLaunchActivity(in Intent intent, IBinder token, int ident, in ActivityInfo info, in Configuration curConfig, in Configuration overrideConfig, in CompatibilityInfo compatInfo, in String referrer, IVoiceInteractor voiceInteractor, int procState, in Bundle state, in PersistableBundle persistentState, in List<ResultInfo> pendingResults, in List<ReferrerIntent> pendingNewIntents, - boolean notResumed, boolean isForward, in ProfilerInfo profilerInfo) = 6; + boolean notResumed, boolean isForward, in ProfilerInfo profilerInfo); void scheduleNewIntent( - in List<ReferrerIntent> intent, IBinder token, boolean andPause) = 7; + in List<ReferrerIntent> intent, IBinder token, boolean andPause); void scheduleDestroyActivity(IBinder token, boolean finished, - int configChanges) = 8; + int configChanges); void scheduleReceiver(in Intent intent, in ActivityInfo info, in CompatibilityInfo compatInfo, int resultCode, in String data, in Bundle extras, boolean sync, - int sendingUser, int processState) = 9; + int sendingUser, int processState); void scheduleCreateService(IBinder token, in ServiceInfo info, - in CompatibilityInfo compatInfo, int processState) = 10; - void scheduleStopService(IBinder token) = 11; + in CompatibilityInfo compatInfo, int processState); + void scheduleStopService(IBinder token); void bindApplication(in String packageName, in ApplicationInfo info, in List<ProviderInfo> providers, in ComponentName testName, in ProfilerInfo profilerInfo, in Bundle testArguments, @@ -87,77 +83,73 @@ oneway interface IApplicationThread { int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode, boolean persistent, in Configuration config, in CompatibilityInfo compatInfo, in Map services, - in Bundle coreSettings, in String buildSerial) = 12; - void scheduleExit() = 13; - void scheduleConfigurationChanged(in Configuration config) = 15; + in Bundle coreSettings, in String buildSerial); + void scheduleExit(); + void scheduleConfigurationChanged(in Configuration config); void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId, - int flags, in Intent args) = 16; - void updateTimeZone() = 17; - void processInBackground() = 18; + int flags, in Intent args); + void updateTimeZone(); + void processInBackground(); void scheduleBindService(IBinder token, - in Intent intent, boolean rebind, int processState) = 19; + in Intent intent, boolean rebind, int processState); void scheduleUnbindService(IBinder token, - in Intent intent) = 20; + in Intent intent); void dumpService(in ParcelFileDescriptor fd, IBinder servicetoken, - in String[] args) = 21; + in String[] args); void scheduleRegisteredReceiver(IIntentReceiver receiver, in Intent intent, int resultCode, in String data, in Bundle extras, boolean ordered, - boolean sticky, int sendingUser, int processState) = 22; - void scheduleLowMemory() = 23; + boolean sticky, int sendingUser, int processState); + void scheduleLowMemory(); void scheduleActivityConfigurationChanged(IBinder token, in Configuration overrideConfig, - boolean reportToActivity) = 24; + boolean reportToActivity); void scheduleRelaunchActivity(IBinder token, in List<ResultInfo> pendingResults, in List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed, - in Configuration config, in Configuration overrideConfig, boolean preserveWindow) = 25; - void scheduleSleeping(IBinder token, boolean sleeping) = 26; - void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType) = 27; - void setSchedulingGroup(int group) = 28; + in Configuration config, in Configuration overrideConfig, boolean preserveWindow); + void scheduleSleeping(IBinder token, boolean sleeping); + void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType); + void setSchedulingGroup(int group); void scheduleCreateBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, - int backupMode) = 29; + int backupMode); void scheduleDestroyBackupAgent(in ApplicationInfo app, - in CompatibilityInfo compatInfo) = 30; - void scheduleOnNewActivityOptions(IBinder token, in Bundle options) = 31; - void scheduleSuicide() = 32; - void dispatchPackageBroadcast(int cmd, in String[] packages) = 33; - void scheduleCrash(in String msg) = 34; - void dumpHeap(boolean managed, in String path, in ParcelFileDescriptor fd) = 35; + in CompatibilityInfo compatInfo); + void scheduleOnNewActivityOptions(IBinder token, in Bundle options); + void scheduleSuicide(); + void dispatchPackageBroadcast(int cmd, in String[] packages); + void scheduleCrash(in String msg); + void dumpHeap(boolean managed, in String path, in ParcelFileDescriptor fd); void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, - in String[] args) = 36; - void clearDnsCache() = 37; + in String[] args); + void clearDnsCache(); void setHttpProxy(in String proxy, in String port, in String exclList, - in Uri pacFileUrl) = 38; - void setCoreSettings(in Bundle coreSettings) = 39; - void updatePackageCompatibilityInfo(in String pkg, in CompatibilityInfo info) = 40; - void scheduleTrimMemory(int level) = 41; + in Uri pacFileUrl); + void setCoreSettings(in Bundle coreSettings); + void updatePackageCompatibilityInfo(in String pkg, in CompatibilityInfo info); + void scheduleTrimMemory(int level); void dumpMemInfo(in ParcelFileDescriptor fd, in Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable, - in String[] args) = 42; - void dumpGfxInfo(in ParcelFileDescriptor fd, in String[] args) = 43; + in String[] args); + void dumpGfxInfo(in ParcelFileDescriptor fd, in String[] args); void dumpProvider(in ParcelFileDescriptor fd, IBinder servicetoken, - in String[] args) = 44; - void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args) = 45; - void unstableProviderDied(IBinder provider) = 46; + in String[] args); + void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args); + void unstableProviderDied(IBinder provider); void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, - int requestType, int sessionId) = 47; - void scheduleTranslucentConversionComplete(IBinder token, boolean timeout) = 48; - void setProcessState(int state) = 49; - void scheduleInstallProvider(in ProviderInfo provider) = 50; - void updateTimePrefs(boolean is24Hour) = 51; - void scheduleCancelVisibleBehind(IBinder token) = 52; - void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled) = 53; - void scheduleEnterAnimationComplete(IBinder token) = 54; - void notifyCleartextNetwork(in byte[] firstPacket) = 55; - void startBinderTracking() = 56; - void stopBinderTrackingAndDump(in ParcelFileDescriptor fd) = 57; - void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) = 58; + int requestType, int sessionId); + void scheduleTranslucentConversionComplete(IBinder token, boolean timeout); + void setProcessState(int state); + void scheduleInstallProvider(in ProviderInfo provider); + void updateTimePrefs(boolean is24Hour); + void scheduleCancelVisibleBehind(IBinder token); + void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled); + void scheduleEnterAnimationComplete(IBinder token); + void notifyCleartextNetwork(in byte[] firstPacket); + void startBinderTracking(); + void stopBinderTrackingAndDump(in ParcelFileDescriptor fd); + void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode); void schedulePictureInPictureModeChanged(IBinder token, - boolean isInPictureInPictureMode) = 59; + boolean isInPictureInPictureMode); void scheduleLocalVoiceInteractionStarted(IBinder token, - IVoiceInteractor voiceInteractor) = 60; - void handleTrustStorageUpdate() = 61; - void attachAgent(String path) = 62; - /** - * Don't change the existing transaction Ids as they could be used in the native code. - * When adding a new method, assign the next available transaction id. - */ + IVoiceInteractor voiceInteractor); + void handleTrustStorageUpdate(); + void attachAgent(String path); }
\ No newline at end of file diff --git a/core/java/android/app/IEphemeralResolver.aidl b/core/java/android/app/IEphemeralResolver.aidl index e0cef83cb9c7..260b80c7d634 100644 --- a/core/java/android/app/IEphemeralResolver.aidl +++ b/core/java/android/app/IEphemeralResolver.aidl @@ -23,6 +23,6 @@ oneway interface IEphemeralResolver { void getEphemeralResolveInfoList(IRemoteCallback callback, in int[] digestPrefix, int sequence); - void getEphemeralIntentFilterList(IRemoteCallback callback, in int[] digestPrefix, + void getEphemeralIntentFilterList(IRemoteCallback callback, String hostName, int sequence); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 261fde2883d3..1fd082f4683e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2803,10 +2803,6 @@ public class Notification implements Parcelable * It will be played using the {@link #AUDIO_ATTRIBUTES_DEFAULT default audio attributes} * for notifications. * - * <p> - * A notification that is noisy is more likely to be presented as a heads-up notification. - * </p> - * * @see Notification#sound */ public Builder setSound(Uri sound) { @@ -2820,9 +2816,6 @@ public class Notification implements Parcelable * * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants. * - * <p> - * A notification that is noisy is more likely to be presented as a heads-up notification. - * </p> * @deprecated use {@link #setSound(Uri, AudioAttributes)} instead. * @see Notification#sound */ @@ -2837,10 +2830,6 @@ public class Notification implements Parcelable * Set the sound to play, along with specific {@link AudioAttributes audio attributes} to * use during playback. * - * <p> - * A notification that is noisy is more likely to be presented as a heads-up notification. - * </p> - * * @see Notification#sound */ public Builder setSound(Uri sound, AudioAttributes audioAttributes) { diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index f259c6d1f0c5..bfabc0d80aa2 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -48,8 +48,9 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_IMPORTANCE = "importance"; private static final String ATT_LIGHTS = "lights"; private static final String ATT_VIBRATION = "vibration"; - private static final String ATT_RINGTONE = "ringtone"; - private static final String ATT_USER_APPROVED = "approved"; + private static final String ATT_SOUND = "sound"; + //TODO: add audio attributes support + private static final String ATT_AUDIO_ATTRIBUTES = "audio_attributes"; private static final String ATT_USER_LOCKED = "locked"; /** @@ -81,7 +82,7 @@ public final class NotificationChannel implements Parcelable { * @hide */ @SystemApi - public static final int USER_LOCKED_RINGTONE = 0x00000020; + public static final int USER_LOCKED_SOUND = 0x00000020; private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE; @@ -93,7 +94,7 @@ public final class NotificationChannel implements Parcelable { private int mImportance = DEFAULT_IMPORTANCE; private boolean mBypassDnd; private int mLockscreenVisibility = DEFAULT_VISIBILITY; - private Uri mRingtone; + private Uri mSound; private boolean mLights; private boolean mVibration; private int mUserLockedFields; @@ -124,9 +125,9 @@ public final class NotificationChannel implements Parcelable { mBypassDnd = in.readByte() != 0; mLockscreenVisibility = in.readInt(); if (in.readByte() != 0) { - mRingtone = Uri.CREATOR.createFromParcel(in); + mSound = Uri.CREATOR.createFromParcel(in); } else { - mRingtone = null; + mSound = null; } mLights = in.readByte() != 0; mVibration = in.readByte() != 0; @@ -145,9 +146,9 @@ public final class NotificationChannel implements Parcelable { dest.writeInt(mImportance); dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0); dest.writeInt(mLockscreenVisibility); - if (mRingtone != null) { + if (mSound != null) { dest.writeByte((byte) 1); - mRingtone.writeToParcel(dest, 0); + mSound.writeToParcel(dest, 0); } else { dest.writeByte((byte) 0); } @@ -202,12 +203,12 @@ public final class NotificationChannel implements Parcelable { // Modifiable by apps on channel creation. /** - * Sets the ringtone that should be played for notifications posted to this channel if - * the notifications don't supply a ringtone. Only modifiable before the channel is submitted + * Sets the sound that should be played for notifications posted to this channel if + * the notifications don't supply a sound. Only modifiable before the channel is submitted * to the NotificationManager. */ - public void setRingtone(Uri ringtone) { - this.mRingtone = ringtone; + public void setSound(Uri sound) { + this.mSound = sound; } /** @@ -261,8 +262,8 @@ public final class NotificationChannel implements Parcelable { /** * Returns the notification sound for this channel. */ - public Uri getRingtone() { - return mRingtone; + public Uri getSound() { + return mSound; } /** @@ -304,7 +305,7 @@ public final class NotificationChannel implements Parcelable { setBypassDnd(Notification.PRIORITY_DEFAULT != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT)); setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY)); - setRingtone(safeUri(parser, ATT_RINGTONE)); + setSound(safeUri(parser, ATT_SOUND)); setLights(safeBool(parser, ATT_LIGHTS, false)); setVibration(safeBool(parser, ATT_VIBRATION, false)); lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); @@ -330,8 +331,8 @@ public final class NotificationChannel implements Parcelable { out.attribute(null, ATT_VISIBILITY, Integer.toString(getLockscreenVisibility())); } - if (getRingtone() != null) { - out.attribute(null, ATT_RINGTONE, getRingtone().toString()); + if (getSound() != null) { + out.attribute(null, ATT_SOUND, getSound().toString()); } if (shouldShowLights()) { out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights())); @@ -364,8 +365,8 @@ public final class NotificationChannel implements Parcelable { if (getLockscreenVisibility() != DEFAULT_VISIBILITY) { record.put(ATT_VISIBILITY, Notification.visibilityToString(getLockscreenVisibility())); } - if (getRingtone() != null) { - record.put(ATT_RINGTONE, getRingtone().toString()); + if (getSound() != null) { + record.put(ATT_SOUND, getSound().toString()); } record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights())); record.put(ATT_VIBRATION, Boolean.toString(shouldVibrate())); @@ -432,8 +433,8 @@ public final class NotificationChannel implements Parcelable { if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) return false; - return getRingtone() != null ? getRingtone().equals( - that.getRingtone()) : that.getRingtone() == null; + return getSound() != null ? getSound().equals( + that.getSound()) : that.getSound() == null; } @@ -444,7 +445,7 @@ public final class NotificationChannel implements Parcelable { result = 31 * result + getImportance(); result = 31 * result + (mBypassDnd ? 1 : 0); result = 31 * result + getLockscreenVisibility(); - result = 31 * result + (getRingtone() != null ? getRingtone().hashCode() : 0); + result = 31 * result + (getSound() != null ? getSound().hashCode() : 0); result = 31 * result + (mLights ? 1 : 0); result = 31 * result + (mVibration ? 1 : 0); result = 31 * result + getUserLockedFields(); @@ -459,7 +460,7 @@ public final class NotificationChannel implements Parcelable { ", mImportance=" + mImportance + ", mBypassDnd=" + mBypassDnd + ", mLockscreenVisibility=" + mLockscreenVisibility + - ", mRingtone=" + mRingtone + + ", mSound=" + mSound + ", mLights=" + mLights + ", mVibration=" + mVibration + ", mUserLockedFields=" + mUserLockedFields + diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 5ca39b0eb80e..0196312580fd 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6749,4 +6749,54 @@ public class DevicePolicyManager { throw re.rethrowFromSystemServer(); } } + + /** + * Called by the system to get the time at which the device owner last retrieved security + * logging entries. + * + * @return the time at which the device owner most recently retrieved security logging entries, + * in milliseconds since epoch; -1 if security logging entries were never retrieved. + * + * @hide + */ + public long getLastSecurityLogRetrievalTime() { + try { + return mService.getLastSecurityLogRetrievalTime(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by the system to get the time at which the device owner last requested a bug report. + * + * @return the time at which the device owner most recently requested a bug report, in + * milliseconds since epoch; -1 if a bug report was never requested. + * + * @hide + */ + public long getLastBugReportRequestTime() { + try { + return mService.getLastBugReportRequestTime(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by the system to get the time at which the device owner last retrieved network logging + * events. + * + * @return the time at which the device owner most recently retrieved network logging events, in + * milliseconds since epoch; -1 if network logging events were never retrieved. + * + * @hide + */ + public long getLastNetworkLogRetrievalTime() { + try { + return mService.getLastNetworkLogRetrievalTime(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index a2546c024962..d14e0d0dfdf0 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -325,4 +325,8 @@ interface IDevicePolicyManager { boolean bindDeviceAdminServiceAsUser(in ComponentName admin, IApplicationThread caller, IBinder token, in Intent service, IServiceConnection connection, int flags, int targetUserId); + + long getLastSecurityLogRetrievalTime(); + long getLastBugReportRequestTime(); + long getLastNetworkLogRetrievalTime(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 052fa61f5a5c..b3dd0e56caf9 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3514,6 +3514,36 @@ public abstract class PackageManager { public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags); /** + * Return a List of all application packages that are installed on the device, for a specific + * user. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all applications including + * those deleted with {@code DONT_DELETE_DATA} (partially installed apps with data directory) + * will be returned. + * + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * @param userId The user for whom the installed applications are to be listed + * + * @return A List of ApplicationInfo objects, one for each installed application. + * In the unlikely case there are no installed packages, an empty list + * is returned. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the + * application information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). + * @hide + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES + */ + public abstract List<ApplicationInfo> getInstalledApplicationsAsUser( + @ApplicationInfoFlags int flags, @UserIdInt int userId); + + /** * Gets the ephemeral applications the user recently used. Requires * holding "android.permission.ACCESS_EPHEMERAL_APPS". * diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java index 945858e6d3c6..29ea5a07ee9b 100644 --- a/core/java/android/content/pm/ParceledListSlice.java +++ b/core/java/android/content/pm/ParceledListSlice.java @@ -17,12 +17,15 @@ package android.content.pm; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; +import dalvik.system.VMRuntime; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -127,7 +130,11 @@ public class ParceledListSlice<T extends Parcelable> implements Parcelable { } public List<T> getList() { - return mList; + if (VMRuntime.getRuntime().getTargetSdkVersion() > Build.VERSION_CODES.N_MR1) { + return Collections.unmodifiableList(mList); + } else { + return mList; + } } @Override diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 45aeb4acb3b0..025d46d12567 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -88,10 +88,10 @@ interface IUsbManager /* Returns true if the specified USB function is enabled. */ boolean isFunctionEnabled(String function); - /* Sets the current USB function as well as whether USB data - * (for example, MTP exposed pictures) should be made available + /* Sets the current USB function as well as whether USB data + * (for example, MTP exposed pictures) should be made available * on the USB connection. Unlocking data should only be done with - * user involvement, since exposing pictures or other data could + * user involvement, since exposing pictures or other data could * leak sensitive user information. */ void setCurrentFunction(String function, boolean usbDataUnlocked); diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 7a3c95e004c5..8eca43158ef2 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -26,6 +26,8 @@ import android.graphics.drawable.AnimatedVectorDrawable; import dalvik.annotation.optimization.FastNative; +import libcore.util.NativeAllocationRegistry; + /** * <p>A display list records a series of graphics related operations and can replay * them later. Display lists are usually built by recording operations on a @@ -130,13 +132,20 @@ import dalvik.annotation.optimization.FastNative; */ public class RenderNode { + // Use a Holder to allow static initialization in the boot image. + private static class NoImagePreloadHolder { + public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( + RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024); + } + private boolean mValid; // Do not access directly unless you are ThreadedRenderer - long mNativeRenderNode; + final long mNativeRenderNode; private final View mOwningView; private RenderNode(String name, View owningView) { mNativeRenderNode = nCreate(name); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode); mOwningView = owningView; } @@ -145,6 +154,7 @@ public class RenderNode { */ private RenderNode(long nativePtr) { mNativeRenderNode = nativePtr; + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode); mOwningView = null; } @@ -154,19 +164,7 @@ public class RenderNode { * is not feasible. */ public void destroy() { - if (mNativeRenderNode != 0) { - nFinalize(mNativeRenderNode); - mNativeRenderNode = 0; - } - } - - @Override - protected void finalize() throws Throwable { - try { - destroy(); - } finally { - super.finalize(); - } + // TODO: Removed temporarily } /** @@ -835,7 +833,6 @@ public class RenderNode { // Intentionally not static because it acquires a reference to 'this' private native long nCreate(String name); - private native void nFinalize(long renderNode); private static native long nGetNativeFinalizer(); private static native void nSetDisplayList(long renderNode, long newData); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 5eaabe7c137b..541fbe0528f1 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -111,6 +111,8 @@ import android.widget.TextView.Drawables; import android.widget.TextView.OnEditorActionListener; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; import com.android.internal.util.Preconditions; @@ -1119,14 +1121,26 @@ public class Editor { getInsertionController().show(); mIsInsertionActionModeStartPending = true; handled = true; + MetricsLogger.action( + mTextView.getContext(), + MetricsEvent.TEXT_LONGPRESS, + TextViewMetrics.SUBTYPE_LONG_PRESS_OTHER); } if (!handled && mTextActionMode != null) { if (touchPositionIsInSelection()) { startDragAndDrop(); + MetricsLogger.action( + mTextView.getContext(), + MetricsEvent.TEXT_LONGPRESS, + TextViewMetrics.SUBTYPE_LONG_PRESS_DRAG_AND_DROP); } else { stopTextActionMode(); selectCurrentWordAndStartDrag(); + MetricsLogger.action( + mTextView.getContext(), + MetricsEvent.TEXT_LONGPRESS, + TextViewMetrics.SUBTYPE_LONG_PRESS_SELECTION); } handled = true; } @@ -1134,6 +1148,12 @@ public class Editor { // Start a new selection if (!handled) { handled = selectCurrentWordAndStartDrag(); + if (handled) { + MetricsLogger.action( + mTextView.getContext(), + MetricsEvent.TEXT_LONGPRESS, + TextViewMetrics.SUBTYPE_LONG_PRESS_SELECTION); + } } return handled; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 5426a37cdd80..69f463cdd856 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -148,6 +148,8 @@ import android.view.textservice.TextServicesManager; import android.widget.RemoteViews.RemoteView; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.FastMath; import com.android.internal.widget.EditableInputConnection; @@ -9685,6 +9687,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (handled) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); if (mEditor != null) mEditor.mDiscardNextActionUp = true; + } else { + MetricsLogger.action( + mContext, + MetricsEvent.TEXT_LONGPRESS, + TextViewMetrics.SUBTYPE_LONG_PRESS_OTHER); } return handled; diff --git a/core/java/android/widget/TextViewMetrics.java b/core/java/android/widget/TextViewMetrics.java new file mode 100644 index 000000000000..0a14d3e8b466 --- /dev/null +++ b/core/java/android/widget/TextViewMetrics.java @@ -0,0 +1,40 @@ +/* + * 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.widget; + +/** + * {@link com.android.internal.logging.MetricsLogger} values for TextView. + * + * @hide + */ +final class TextViewMetrics { + + private TextViewMetrics() {} + + /** + * Long press on TextView - no special classification. + */ + static final int SUBTYPE_LONG_PRESS_OTHER = 0; + /** + * Long press on TextView - selection started. + */ + static final int SUBTYPE_LONG_PRESS_SELECTION = 1; + /** + * Long press on TextView - drag and drop started. + */ + static final int SUBTYPE_LONG_PRESS_DRAG_AND_DROP = 2; +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index f5429a1c5082..a4e957638406 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -277,7 +277,8 @@ LOCAL_SHARED_LIBRARIES := \ libradio_metadata \ libnativeloader \ libmemunreachable \ - libhidl \ + libhidlbase \ + libhidltransport \ libhwbinder \ LOCAL_SHARED_LIBRARIES += \ diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index e10fdbdb2845..34568391167d 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -915,6 +915,16 @@ namespace PaintGlue { paint->setLetterSpacing(letterSpacing); } + static jfloat getWordSpacing(jlong paintHandle) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + return paint->getWordSpacing(); + } + + static void setWordSpacing(jlong paintHandle, jfloat wordSpacing) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + paint->setWordSpacing(wordSpacing); + } + static jint getHyphenEdit(jlong paintHandle, jint hyphen) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); return paint->getHyphenEdit(); @@ -1043,6 +1053,8 @@ static const JNINativeMethod methods[] = { {"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX}, {"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing}, {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing}, + {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing}, + {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing}, {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit}, {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit}, {"nAscent","(JJ)F", (void*) PaintGlue::ascent}, diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index f88de51a9a12..dd2a7a98b7a0 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -124,10 +124,6 @@ static void releaseRenderNode(RenderNode* renderNode) { renderNode->decStrong(0); } -static void android_view_RenderNode_finalize(JNIEnv* env, jobject clazz, jlong renderNodePtr) { - releaseRenderNode(reinterpret_cast<RenderNode*>(renderNodePtr)); -} - static jlong android_view_RenderNode_getNativeFinalizer(JNIEnv* env, jobject clazz) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseRenderNode)); @@ -654,7 +650,6 @@ static const JNINativeMethod gMethods[] = { // Regular JNI // ---------------------------------------------------------------------------- { "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create }, - { "nFinalize", "(J)V", (void*) android_view_RenderNode_finalize }, { "nGetNativeFinalizer", "()J", (void*) android_view_RenderNode_getNativeFinalizer }, { "nSetDisplayList", "(JJ)V", (void*) android_view_RenderNode_setDisplayList }, { "nOutput", "(J)V", (void*) android_view_RenderNode_output }, diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml index 1d7a45b31eb6..c66ed121f9ef 100755 --- a/core/res/res/values-mcc204-mnc04/config.xml +++ b/core/res/res/values-mcc204-mnc04/config.xml @@ -25,12 +25,15 @@ --> <integer name="config_mobile_mtu">1358</integer> - <!-- Flag indicating whether strict threshold is used, or lenient threshold is used, - when evaluating RSRP for LTE antenna bar display - 0. Strict threshold - 1. Lenient threshold - --> - <integer name="config_LTE_RSRP_threshold_type">0</integer> + <!--Thresholds for LTE dbm in status bar--> + <integer-array translatable="false" name="config_lteDbmThresholds"> + <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN --> + <item>-115</item> <!-- SIGNAL_STRENGTH_POOR --> + <item>-105</item> <!-- SIGNAL_STRENGTH_MODERATE --> + <item>-95</item> <!-- SIGNAL_STRENGTH_GOOD --> + <item>-85</item> <!-- SIGNAL_STRENGTH_GREAT --> + <item>-44</item> + </integer-array> <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true;BAE0000000000000</string> </resources> diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml index a0a361b599dd..a210f5b1674e 100755 --- a/core/res/res/values-mcc311-mnc480/config.xml +++ b/core/res/res/values-mcc311-mnc480/config.xml @@ -50,12 +50,15 @@ <bool name="config_auto_attach_data_on_creation">false</bool> - <!-- Flag indicating whether strict threshold is used, or lenient threshold is used, - when evaluating RSRP for LTE antenna bar display - 0. Strict threshold - 1. Lenient threshold - --> - <integer name="config_LTE_RSRP_threshold_type">0</integer> + <!--Thresholds for LTE dbm in status bar--> + <integer-array translatable="false" name="config_lteDbmThresholds"> + <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN --> + <item>-115</item> <!-- SIGNAL_STRENGTH_POOR --> + <item>-105</item> <!-- SIGNAL_STRENGTH_MODERATE --> + <item>-95</item> <!-- SIGNAL_STRENGTH_GOOD --> + <item>-85</item> <!-- SIGNAL_STRENGTH_GREAT --> + <item>-44</item> + </integer-array> <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string> diff --git a/core/res/res/values-watch/config_material.xml b/core/res/res/values-watch/config_material.xml index 529f18b78e4d..03d3637b150d 100644 --- a/core/res/res/values-watch/config_material.xml +++ b/core/res/res/values-watch/config_material.xml @@ -30,6 +30,9 @@ <!-- Always overscan by default to ensure onApplyWindowInsets will always be called. --> <bool name="config_windowOverscanByDefault">true</bool> + <!-- Enable windowSwipeToDismiss. --> + <bool name="config_windowSwipeToDismiss">true</bool> + <!-- Style the scrollbars accoridngly. --> <drawable name="config_scrollbarThumbVertical">@drawable/scrollbar_vertical_thumb</drawable> <drawable name="config_scrollbarTrackVertical">@drawable/scrollbar_vertical_track</drawable> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 996fd55f69bd..d4119d072a46 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2326,12 +2326,15 @@ <bool name="config_sms_force_7bit_encoding">false</bool> - <!-- Flag indicating whether strict threshold is used, or lenient threshold is used, - when evaluating RSRP for LTE antenna bar display - 0. Strict threshold - 1. Lenient threshold - --> - <integer name="config_LTE_RSRP_threshold_type">1</integer> + <!--Thresholds for LTE dbm in status bar--> + <integer-array translatable="false" name="config_lteDbmThresholds"> + <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN --> + <item>-128</item> <!-- SIGNAL_STRENGTH_POOR --> + <item>-118</item> <!-- SIGNAL_STRENGTH_MODERATE --> + <item>-108</item> <!-- SIGNAL_STRENGTH_GOOD --> + <item>-98</item> <!-- SIGNAL_STRENGTH_GREAT --> + <item>-44</item> + </integer-array> <!-- Enabled built-in zen mode condition providers --> <string-array translatable="false" name="config_system_condition_providers"> diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml index 840a551f914f..8737df84e060 100644 --- a/core/res/res/values/config_material.xml +++ b/core/res/res/values/config_material.xml @@ -32,6 +32,9 @@ <!-- True if windowOverscan should be on by default. --> <bool name="config_windowOverscanByDefault">false</bool> + <!-- True if windowSwipeToDismiss should be on by default. --> + <bool name="config_windowSwipeToDismiss">false</bool> + <!-- True if preference fragment should clip to padding. --> <bool name="config_preferenceFragmentClipToPadding">true</bool> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index cce02f299fd8..d42ec9067ac4 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2906,13 +2906,17 @@ <!-- Choice in the ringtone picker. If chosen, the default ringtone will be used. --> <string name="ringtone_default">Default ringtone</string> <!-- Choice in the ringtone picker. If chosen, the default ringtone will be used. This fills in the actual ringtone's title into the message. --> - <string name="ringtone_default_with_actual">Default ringtone (<xliff:g id="actual_ringtone">%1$s</xliff:g>)</string> + <string name="ringtone_default_with_actual">Default (<xliff:g id="actual_ringtone">%1$s</xliff:g>)</string> <!-- Choice in the ringtone picker. If chosen, there will be silence instead of a ringtone played. --> <string name="ringtone_silent">None</string> <!-- The title of the ringtone picker dialog. --> <string name="ringtone_picker_title">Ringtones</string> + <!-- The title of the alarm sound picker dialog [CHAR LIMIT=100] --> + <string name="ringtone_picker_title_alarm">Alarm sounds</string> + <!-- The title of the notification sound picker dialog [CHAR LIMIT=100] --> + <string name="ringtone_picker_title_notification">Notification sounds</string> <!-- If there is ever a ringtone set for some setting, but that ringtone can no longer be resolved, t his is shown instead. For example, if the ringtone was on a SD card and it had been removed, this woudl be shown for ringtones on that SD card. --> - <string name="ringtone_unknown">Unknown ringtone</string> + <string name="ringtone_unknown">Unknown</string> <!-- A notification is shown when there are open wireless networks nearby. This is the notification's title. --> <plurals name="wifi_available"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6c0dc3529b16..c719664c38a8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -851,6 +851,8 @@ <java-symbol type="string" name="ringtone_default" /> <java-symbol type="string" name="ringtone_default_with_actual" /> <java-symbol type="string" name="ringtone_picker_title" /> + <java-symbol type="string" name="ringtone_picker_title_alarm" /> + <java-symbol type="string" name="ringtone_picker_title_notification" /> <java-symbol type="string" name="ringtone_silent" /> <java-symbol type="string" name="ringtone_unknown" /> <java-symbol type="string" name="roamingText0" /> @@ -2296,7 +2298,7 @@ <java-symbol type="dimen" name="cascading_menus_min_smallest_width" /> <!-- From SignalStrength --> - <java-symbol type="integer" name="config_LTE_RSRP_threshold_type" /> + <java-symbol type="array" name="config_lteDbmThresholds" /> <java-symbol type="string" name="android_system_label" /> <java-symbol type="string" name="system_error_wipe_data" /> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index ff8693bbbdad..0de773bc3724 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -175,6 +175,7 @@ please see themes_device_defaults.xml. <item name="windowSharedElementExitTransition">@transition/move</item> <item name="windowContentTransitions">false</item> <item name="windowActivityTransitions">true</item> + <item name="windowSwipeToDismiss">@bool/config_windowSwipeToDismiss</item> <!-- Dialog attributes --> <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item> @@ -536,6 +537,7 @@ please see themes_device_defaults.xml. <item name="windowSharedElementExitTransition">@transition/move</item> <item name="windowContentTransitions">false</item> <item name="windowActivityTransitions">true</item> + <item name="windowSwipeToDismiss">@bool/config_windowSwipeToDismiss</item> <!-- Dialog attributes --> <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item> diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk index 9e45d099b669..d7b38e844b5e 100644 --- a/core/tests/coretests/apks/install_jni_lib/Android.mk +++ b/core/tests/coretests/apks/install_jni_lib/Android.mk @@ -19,8 +19,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ com_android_frameworks_coretests_JNITest.cpp -LOCAL_SHARED_LIBRARIES := \ - libnativehelper +LOCAL_SDK_VERSION := 16 LOCAL_CFLAGS += -Wall -Werror diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp index 8d9119275bc8..0cf3a84a3859 100644 --- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp +++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp @@ -14,41 +14,23 @@ * limitations under the License. */ -#include "nativehelper/JNIHelp.h" +#include <jni.h> -namespace android { - -static jint checkFunction(JNIEnv*, jclass) { +extern "C" JNIEXPORT +jint JNICALL Java_com_android_frameworks_coretests_JNITests_checkFunction(JNIEnv*, jclass) { return 1; } -static const JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - { "checkFunction", "()I", (void*) checkFunction }, -}; - -int register_com_android_frameworks_coretests_JNITests(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/frameworks/coretests/JNITests", sMethods, - NELEM(sMethods)); -} - -} - /* * JNI Initialization */ jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) { JNIEnv *e; - int status; // Check JNI version if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) { return JNI_ERR; } - if ((status = android::register_com_android_frameworks_coretests_JNITests(e)) < 0) { - return JNI_ERR; - } - return JNI_VERSION_1_6; } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 98d45dc33ead..554e5d2614dd 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1442,6 +1442,28 @@ public class Paint { } /** + * Return the paint's word-spacing for text. The default value is 0. + * + * @return the paint's word-spacing for drawing text. + * @hide + */ + public float getWordSpacing() { + return nGetWordSpacing(mNativePaint); + } + + /** + * Set the paint's word-spacing for text. The default value is 0. + * The value is in pixels (note the units are not the same as for + * letter-spacing). + * + * @param wordSpacing set the paint's word-spacing for drawing text. + * @hide + */ + public void setWordSpacing(float wordSpacing) { + nSetWordSpacing(mNativePaint, wordSpacing); + } + + /** * Returns the font feature settings. The format is the same as the CSS * font-feature-settings attribute: * <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop"> @@ -2711,6 +2733,10 @@ public class Paint { @CriticalNative private static native void nSetLetterSpacing(long paintPtr, float letterSpacing); @CriticalNative + private static native float nGetWordSpacing(long paintPtr); + @CriticalNative + private static native void nSetWordSpacing(long paintPtr, float wordSpacing); + @CriticalNative private static native int nGetHyphenEdit(long paintPtr); @CriticalNative private static native void nSetHyphenEdit(long paintPtr, int hyphen); diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java index 6763dd1970ae..318bfb6bfd39 100644 --- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java +++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java @@ -218,4 +218,13 @@ public class PaintTest extends AndroidTestCase { assertEquals(width, p.measureText(bidiText), 1.0f); } } + + public void testSetGetWordSpacing() { + Paint p = new Paint(); + assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0. + p.setWordSpacing(1.0f); + assertEquals(1.0f, p.getWordSpacing()); + p.setWordSpacing(-2.0f); + assertEquals(-2.0f, p.getWordSpacing()); + } } diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 47220508f2bd..fdf4d52f357b 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -24,6 +24,7 @@ hwui_src_files := \ pipeline/skia/ReorderBarrierDrawables.cpp \ pipeline/skia/SkiaDisplayList.cpp \ pipeline/skia/SkiaOpenGLPipeline.cpp \ + pipeline/skia/SkiaOpenGLReadback.cpp \ pipeline/skia/SkiaPipeline.cpp \ pipeline/skia/SkiaProfileRenderer.cpp \ pipeline/skia/SkiaRecordingCanvas.cpp \ @@ -84,6 +85,7 @@ hwui_src_files := \ LayerUpdateQueue.cpp \ Matrix.cpp \ OpDumper.cpp \ + OpenGLReadback.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ @@ -96,7 +98,6 @@ hwui_src_files := \ Properties.cpp \ PropertyValuesAnimatorSet.cpp \ PropertyValuesHolder.cpp \ - Readback.cpp \ RecordingCanvas.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ diff --git a/libs/hwui/Readback.cpp b/libs/hwui/OpenGLReadback.cpp index 1645218495eb..408159b8f33a 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/OpenGLReadback.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Readback.h" +#include "OpenGLReadback.h" #include "Caches.h" #include "Image.h" @@ -31,8 +31,81 @@ namespace android { namespace uirenderer { -static CopyResult copyTextureInto(Caches& caches, RenderState& renderState, - Texture& sourceTexture, Matrix4& texTransform, const Rect& srcRect, +CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) { + ATRACE_CALL(); + // Setup the source + sp<GraphicBuffer> sourceBuffer; + sp<Fence> sourceFence; + Matrix4 texTransform; + status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, + texTransform.data); + texTransform.invalidateType(); + if (err != NO_ERROR) { + ALOGW("Failed to get last queued buffer, error = %d", err); + return CopyResult::UnknownError; + } + if (!sourceBuffer.get()) { + ALOGW("Surface doesn't have any previously queued frames, nothing to readback from"); + return CopyResult::SourceEmpty; + } + if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) { + ALOGW("Surface is protected, unable to copy from it"); + return CopyResult::SourceInvalid; + } + err = sourceFence->wait(500 /* ms */); + if (err != NO_ERROR) { + ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); + return CopyResult::Timeout; + } + + return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap); +} + +CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, + Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { + mRenderThread.eglManager().initialize(); + // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via + // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES + // to be able to properly sample from the buffer. + + // Create the EGLImage object that maps the GraphicBuffer + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer(); + EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; + + EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); + + if (sourceImage == EGL_NO_IMAGE_KHR) { + ALOGW("eglCreateImageKHR failed (%#x)", eglGetError()); + return CopyResult::UnknownError; + } + + CopyResult copyResult = copyImageInto(sourceImage, texTransform, graphicBuffer->getWidth(), + graphicBuffer->getHeight(), srcRect, bitmap); + + // All we're flushing & finishing is the deletion of the texture since + // copyImageInto already did a major flush & finish as an implicit + // part of glReadPixels, so this shouldn't pose any major stalls. + glFinish(); + eglDestroyImageKHR(display, sourceImage); + return copyResult; +} + +CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { + Rect srcRect; + Matrix4 transform; + transform.loadScale(1, -1, 1); + transform.translate(0, -1); + return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, + Texture& sourceTexture, const Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { int destWidth = bitmap->width(); int destHeight = bitmap->height(); @@ -134,88 +207,40 @@ static CopyResult copyTextureInto(Caches& caches, RenderState& renderState, return CopyResult::Success; } -CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, - Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { - ATRACE_CALL(); - renderThread.eglManager().initialize(); +CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, + const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect, + SkBitmap* bitmap) { Caches& caches = Caches::getInstance(); - - // Setup the source - sp<GraphicBuffer> sourceBuffer; - sp<Fence> sourceFence; - Matrix4 texTransform; - status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, - texTransform.data); - texTransform.invalidateType(); - if (err != NO_ERROR) { - ALOGW("Failed to get last queued buffer, error = %d", err); - return CopyResult::UnknownError; - } - if (!sourceBuffer.get()) { - ALOGW("Surface doesn't have any previously queued frames, nothing to readback from"); - return CopyResult::SourceEmpty; - } - if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) { - ALOGW("Surface is protected, unable to copy from it"); - return CopyResult::SourceInvalid; - } - err = sourceFence->wait(500 /* ms */); - if (err != NO_ERROR) { - ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); - return CopyResult::Timeout; - } - - // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via - // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES - // to be able to properly sample from the buffer. - - // Create the EGLImage object that maps the GraphicBuffer - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer(); - EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; - - EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); - - if (sourceImage == EGL_NO_IMAGE_KHR) { - ALOGW("eglCreateImageKHR failed (%#x)", eglGetError()); - return CopyResult::UnknownError; - } GLuint sourceTexId; // Create a 2D texture to sample from the EGLImage glGenTextures(1, &sourceTexId); caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, sourceImage); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage); GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status); - eglDestroyImageKHR(display, sourceImage); return CopyResult::UnknownError; } Texture sourceTexture(caches); - sourceTexture.wrap(sourceTexId, sourceBuffer->getWidth(), - sourceBuffer->getHeight(), 0, 0 /* total lie */, GL_TEXTURE_EXTERNAL_OES); + sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */, + GL_TEXTURE_EXTERNAL_OES); - CopyResult copyResult = copyTextureInto(caches, renderThread.renderState(), - sourceTexture, texTransform, srcRect, bitmap); + CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), + sourceTexture, imgTransform, srcRect, bitmap); sourceTexture.deleteTexture(); - // All we're flushing & finishing is the deletion of the texture since - // copyTextureInto already did a major flush & finish as an implicit - // part of glReadPixels, so this shouldn't pose any major stalls. - glFinish(); - eglDestroyImageKHR(display, sourceImage); return copyResult; } -CopyResult Readback::copyTextureLayerInto(renderthread::RenderThread& renderThread, +bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, Layer& layer, SkBitmap* bitmap) { - ATRACE_CALL(); - return copyTextureInto(Caches::getInstance(), renderThread.renderState(), - layer.getTexture(), layer.getTexTransform(), Rect(), bitmap); + return CopyResult::Success == copyTextureInto(Caches::getInstance(), + renderThread.renderState(), layer.getTexture(), layer.getTexTransform(), + Rect(), bitmap); } + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h new file mode 100644 index 000000000000..f4ebabcdebe5 --- /dev/null +++ b/libs/hwui/OpenGLReadback.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#pragma once + +#include "Readback.h" + +namespace android { +namespace uirenderer { + +class Matrix4; +class Layer; + +class OpenGLReadback : public Readback { +public: + virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) override; + virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, + SkBitmap* bitmap) override; + +protected: + explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {} + virtual ~OpenGLReadback() {} + + virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0; +private: + CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, + const Rect& srcRect, SkBitmap* bitmap); +}; + +class OpenGLReadbackImpl : public OpenGLReadback { +public: + OpenGLReadbackImpl(renderthread::RenderThread& thread) : OpenGLReadback(thread) {} + + /** + * Copies the layer's contents into the provided bitmap. + */ + static bool copyLayerInto(renderthread::RenderThread& renderThread, Layer& layer, + SkBitmap* bitmap); + +protected: + virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override; +}; + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index 55c943c0ebee..b76395301a21 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -23,10 +23,9 @@ #include <gui/Surface.h> namespace android { +class GraphicBuffer; namespace uirenderer { -class Layer; - // Keep in sync with PixelCopy.java codes enum class CopyResult { Success = 0, @@ -42,15 +41,15 @@ public: /** * Copies the surface's most recently queued buffer into the provided bitmap. */ - static CopyResult copySurfaceInto(renderthread::RenderThread& renderThread, - Surface& surface, const Rect& srcRect, SkBitmap* bitmap); + virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) = 0; + virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0; - /** - * Copies the TextureLayer's texture content (thus, the currently rendering buffer) into the - * provided bitmap. - */ - static CopyResult copyTextureLayerInto(renderthread::RenderThread& renderThread, - Layer& layer, SkBitmap* bitmap); +protected: + explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {} + virtual ~Readback() {} + + renderthread::RenderThread& mRenderThread; }; } // namespace uirenderer diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index c028f1158e70..d6b6548c47e2 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -459,14 +459,15 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { } void Bitmap::getSkBitmap(SkBitmap* outBitmap) { + outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); if (isHardware()) { - //TODO: use readback to get pixels - LOG_ALWAYS_FATAL("Not implemented"); + ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation"); + outBitmap->allocPixels(info()); + uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap); return; } outBitmap->setInfo(info(), rowBytes()); outBitmap->setPixelRef(this); - outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); } void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) { diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index a52abfc9888a..f172473d1652 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -65,23 +65,6 @@ void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, bounds->mBottom = skBounds.fBottom; } -const void* MinikinFontSkia::GetTable(uint32_t tag, size_t* size, - minikin::MinikinDestroyFunc* destroy) { - // we don't have a buffer to the font data, copy to own buffer - const size_t tableSize = mTypeface->getTableSize(tag); - *size = tableSize; - if (tableSize == 0) { - return nullptr; - } - void* buf = malloc(tableSize); - if (buf == nullptr) { - return nullptr; - } - mTypeface->getTableData(tag, 0, tableSize, buf); - *destroy = free; - return buf; -} - SkTypeface *MinikinFontSkia::GetSkTypeface() const { return mTypeface.get(); } diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h index 1ea99fd899a9..3ee916c6e8b1 100644 --- a/libs/hwui/hwui/MinikinSkia.h +++ b/libs/hwui/hwui/MinikinSkia.h @@ -37,8 +37,6 @@ public: void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, const minikin::MinikinPaint &paint) const; - const void* GetTable(uint32_t tag, size_t* size, minikin::MinikinDestroyFunc* destroy); - SkTypeface* GetSkTypeface() const; sk_sp<SkTypeface> RefSkTypeface() const; diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index a06cc37f944e..8dd165c46d21 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -45,6 +45,7 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini minikinPaint->scaleX = paint->getTextScaleX(); minikinPaint->skewX = paint->getTextSkewX(); minikinPaint->letterSpacing = paint->getLetterSpacing(); + minikinPaint->wordSpacing = paint->getWordSpacing(); minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint); minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings(); minikinPaint->hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit()); diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index 10a1db9ace3d..c9b5f0031a7b 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -48,6 +48,14 @@ public: return mLetterSpacing; } + void setWordSpacing(float wordSpacing) { + mWordSpacing = wordSpacing; + } + + float getWordSpacing() const { + return mWordSpacing; + } + void setFontFeatureSettings(const std::string& fontFeatureSettings) { mFontFeatureSettings = fontFeatureSettings; } @@ -82,6 +90,7 @@ public: private: float mLetterSpacing = 0; + float mWordSpacing = 0; std::string mFontFeatureSettings; uint32_t mMinikinLangListId; minikin::FontVariant mFontVariant; diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp index 84122d768089..67427433bb89 100644 --- a/libs/hwui/hwui/PaintImpl.cpp +++ b/libs/hwui/hwui/PaintImpl.cpp @@ -19,18 +19,19 @@ namespace android { Paint::Paint() : - SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0), - mFontVariant(minikin::VARIANT_DEFAULT) { + SkPaint(), mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(), + mMinikinLangListId(0), mFontVariant(minikin::VARIANT_DEFAULT) { } Paint::Paint(const Paint& paint) : SkPaint(paint), - mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings), + mLetterSpacing(paint.mLetterSpacing), mWordSpacing(paint.mWordSpacing), + mFontFeatureSettings(paint.mFontFeatureSettings), mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant), mHyphenEdit(paint.mHyphenEdit) { } Paint::Paint(const SkPaint& paint) : SkPaint(paint), - mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0), + mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0), mFontVariant(minikin::VARIANT_DEFAULT) { } @@ -40,6 +41,7 @@ Paint::~Paint() { Paint& Paint::operator=(const Paint& other) { SkPaint::operator=(other); mLetterSpacing = other.mLetterSpacing; + mWordSpacing = other.mWordSpacing; mFontFeatureSettings = other.mFontFeatureSettings; mMinikinLangListId = other.mMinikinLangListId; mFontVariant = other.mFontVariant; @@ -50,6 +52,7 @@ Paint& Paint::operator=(const Paint& other) { bool operator==(const Paint& a, const Paint& b) { return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) && a.mLetterSpacing == b.mLetterSpacing + && a.mWordSpacing == b.mWordSpacing && a.mFontFeatureSettings == b.mFontFeatureSettings && a.mMinikinLangListId == b.mMinikinLangListId && a.mFontVariant == b.mFontVariant diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index f95d98cac8d6..ca43156e88a1 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -23,10 +23,14 @@ #include "Typeface.h" #include <pthread.h> +#include <fcntl.h> // For tests. +#include <sys/stat.h> // For tests. +#include <sys/mman.h> // For tests. #include "MinikinSkia.h" #include "SkTypeface.h" #include "SkPaint.h" +#include "SkStream.h" // Fot tests. #include <minikin/FontCollection.h> #include <minikin/FontFamily.h> @@ -116,11 +120,18 @@ void Typeface::setDefault(Typeface* face) { void Typeface::setRobotoTypefaceForTest() { const char* kRobotoFont = "/system/fonts/Roboto-Regular.ttf"; - sk_sp<SkTypeface> typeface = SkTypeface::MakeFromFile(kRobotoFont); + + int fd = open(kRobotoFont, O_RDONLY); + LOG_ALWAYS_FATAL_IF(fd == -1, "Failed to open file %s", kRobotoFont); + struct stat st = {}; + LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", kRobotoFont); + void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + std::unique_ptr<SkMemoryStream> fontData(new SkMemoryStream(data, st.st_size)); + sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(fontData.release()); LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont); minikin::FontFamily* family = new minikin::FontFamily(); - minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), nullptr, 0, 0); + minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), data, st.st_size, 0); family->addFont(font); font->Unref(); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 13a0ed852816..f2af4a891b12 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -23,36 +23,41 @@ namespace uirenderer { namespace skiapipeline { void LayerDrawable::onDraw(SkCanvas* canvas) { + DrawLayer(canvas->getGrContext(), canvas, mLayer.get()); +} + +bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) { // transform the matrix based on the layer int saveCount = -1; - if (!mLayer->getTransform().isIdentity()) { + if (!layer->getTransform().isIdentity()) { saveCount = canvas->save(); SkMatrix transform; - mLayer->getTransform().copyTo(transform); + layer->getTransform().copyTo(transform); canvas->concat(transform); } GrGLTextureInfo externalTexture; - externalTexture.fTarget = mLayer->getRenderTarget(); - externalTexture.fID = mLayer->getTextureId(); - GrContext* context = canvas->getGrContext(); + externalTexture.fTarget = layer->getRenderTarget(); + externalTexture.fID = layer->getTextureId(); GrBackendTextureDesc textureDescription; - textureDescription.fWidth = mLayer->getWidth(); - textureDescription.fHeight = mLayer->getHeight(); + textureDescription.fWidth = layer->getWidth(); + textureDescription.fHeight = layer->getHeight(); textureDescription.fConfig = kRGBA_8888_GrPixelConfig; textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin; textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); sk_sp<SkImage> layerImage = SkImage::MakeFromTexture(context, textureDescription); if (layerImage) { SkPaint paint; - paint.setAlpha(mLayer->getAlpha()); - paint.setBlendMode(mLayer->getMode()); - paint.setColorFilter(sk_ref_sp(mLayer->getColorFilter())); + paint.setAlpha(layer->getAlpha()); + paint.setBlendMode(layer->getMode()); + paint.setColorFilter(sk_ref_sp(layer->getColorFilter())); canvas->drawImage(layerImage, 0, 0, &paint); } // restore the original matrix if (saveCount >= 0) { canvas->restoreToCount(saveCount); } + + return layerImage; } }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 91e274475b34..431989519a70 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -33,6 +33,7 @@ class LayerDrawable : public SkDrawable { explicit LayerDrawable(Layer* layer) : mLayer(layer) {} + static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer); protected: virtual SkRect onGetBounds() override { return SkRect::MakeWH(mLayer->getWidth(), mLayer->getHeight()); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 4abaa90974a6..2ad7f74560d6 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -53,11 +53,15 @@ void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer, std::function<void(RenderNode*, TreeInfo&, bool)> childFn) { - // If the prepare tree is triggered by the UI thread then we must force all - // mutable images to be pinned in the GPU cache until the next UI thread - // draw - if (info.mode == TreeInfo::MODE_FULL) { - info.prepareTextures = info.canvasContext.pinImages(mMutableImages); + // If the prepare tree is triggered by the UI thread and no previous call to + // pinImages has failed then we must pin all mutable images in the GPU cache + // until the next UI thread draw. + if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) { + // In the event that pinning failed we prevent future pinImage calls for the + // remainder of this tree traversal and also unpin any currently pinned images + // to free up GPU resources. + info.prepareTextures = false; + info.canvasContext.unpinImages(); } for (auto& child : mChildNodes) { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index f046e4b93db1..7f3474a1bdf3 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -17,9 +17,9 @@ #include "SkiaOpenGLPipeline.h" #include "DeferredLayerUpdater.h" +#include "LayerDrawable.h" #include "renderthread/EglManager.h" #include "renderstate/RenderState.h" -#include "Readback.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" #include "utils/TraceUtils.h" @@ -121,10 +121,16 @@ bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, return *requireSwap; } -bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { - layer->apply(); - return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap) - == CopyResult::Success; +bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { + if (!mRenderThread.getGrContext()) { + return false; + } + + deferredLayer->apply(); + + SkCanvas canvas(*bitmap); + Layer* layer = deferredLayer->backingLayer(); + return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer); } DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp new file mode 100644 index 000000000000..a18d26471a29 --- /dev/null +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#include "SkiaOpenGLReadback.h" + +#include "Matrix.h" +#include "Properties.h" +#include <SkCanvas.h> +#include <SkSurface.h> +#include <gl/GrGLInterface.h> +#include <gl/GrGLTypes.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android::uirenderer::renderthread; + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) { + + GLuint sourceTexId; + glGenTextures(1, &sourceTexId); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage); + + sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext()); + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { + sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); + LOG_ALWAYS_FATAL_IF(!glInterface.get()); + grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend, + (GrBackendContext)glInterface.get())); + } else { + grContext->resetContext(); + } + + GrGLTextureInfo externalTexture; + externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES; + externalTexture.fID = sourceTexId; + + GrBackendTextureDesc textureDescription; + textureDescription.fWidth = imgWidth; + textureDescription.fHeight = imgHeight; + textureDescription.fConfig = kRGBA_8888_GrPixelConfig; + textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin; + textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); + + CopyResult copyResult = CopyResult::UnknownError; + sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription)); + if (image) { + SkAutoLockPixels alp(*bitmap); + + // convert to Skia data structures + const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight); + SkRect skiaSrcRect = srcRect.toSkRect(); + SkMatrix textureMatrix; + imgTransform.copyTo(textureMatrix); + + // remove the y-flip applied to the matrix so that we can scale the srcRect. + // This flip is not needed as we specify the origin of the texture when we + // wrap it as an SkImage. + SkMatrix yFlip = SkMatrix::MakeScale(1, -1); + yFlip.postTranslate(0,1); + textureMatrix.preConcat(yFlip); + + // copy the entire src if the rect is empty + if (skiaSrcRect.isEmpty()) { + skiaSrcRect = bufferRect; + } + + // since the y-flip has been removed we can simply scale & translate + // the source rectangle + textureMatrix.mapRect(&skiaSrcRect); + + if (skiaSrcRect.intersect(bufferRect)) { + SkPoint srcOrigin = SkPoint::Make(skiaSrcRect.fLeft, skiaSrcRect.fTop); + + // if we need to scale the result we must render to an offscreen buffer + if (bitmap->width() != skiaSrcRect.width() + || bitmap->height() != skiaSrcRect.height()) { + sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget( + grContext.get(), SkBudgeted::kYes, bitmap->info()); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, + SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint); + image = scaledSurface->makeImageSnapshot(); + srcOrigin.set(0,0); + } + + if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), + srcOrigin.fX, srcOrigin.fY)) { + copyResult = CopyResult::Success; + } + } + } + + // make sure that we have deleted the texture (in the SkImage) before we + // destroy the EGLImage that it was created from + image.reset(); + return copyResult; +} + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h new file mode 100644 index 000000000000..d914409628d0 --- /dev/null +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#pragma once + +#include "OpenGLReadback.h" + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +class SkiaOpenGLReadback : public OpenGLReadback { +public: + SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {} +protected: + virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override; +}; + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index a4a83efdecf8..c5a40d46dbd0 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -48,9 +48,11 @@ void SkiaPipeline::onDestroyHardwareResources() { bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) { for (SkImage* image : mutableImages) { - mPinnedImages.emplace_back(sk_ref_sp(image)); - // TODO: return false if texture creation fails (see b/32691999) - SkImage_pinAsTexture(image, mRenderThread.getGrContext()); + if (SkImage_pinAsTexture(image, mRenderThread.getGrContext())) { + mPinnedImages.emplace_back(sk_ref_sp(image)); + } else { + return false; + } } return true; } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index c322efb183a9..0174b86d22d5 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -84,7 +84,7 @@ public: * remain in the cache until it has been unpinned. We leverage this feature * to avoid making a CPU copy of the pixels. * - * @return true if the images have been successfully pinned to the GPU cache + * @return true if all images have been successfully pinned to the GPU cache * and false otherwise (e.g. cache limits have been exceeded). */ bool pinImages(std::vector<SkImage*>& mutableImages) { diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp index afeeef86d22c..177a729cbf55 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.cpp +++ b/libs/hwui/renderthread/OpenGLPipeline.cpp @@ -20,7 +20,7 @@ #include "EglManager.h" #include "ProfileRenderer.h" #include "renderstate/RenderState.h" -#include "Readback.h" +#include "OpenGLReadback.h" #include <android/native_window.h> #include <cutils/properties.h> @@ -117,9 +117,9 @@ bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& sc } bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { + ATRACE_CALL(); layer->apply(); - return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap) - == CopyResult::Success; + return OpenGLReadbackImpl::copyLayerInto(mRenderThread, *(layer->backingLayer()), bitmap); } DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 39e5931da361..022e871315a9 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -27,6 +27,8 @@ #include "utils/Macros.h" #include "utils/TimeUtils.h" +#include <ui/GraphicBuffer.h> + namespace android { namespace uirenderer { namespace renderthread { @@ -602,8 +604,8 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observer) { CREATE_BRIDGE4(copySurfaceInto, RenderThread* thread, Surface* surface, Rect srcRect, SkBitmap* bitmap) { - return (void*) Readback::copySurfaceInto(*args->thread, - *args->surface, args->srcRect, args->bitmap); + return (void*)args->thread->readback().copySurfaceInto(*args->surface, + args->srcRect, args->bitmap); } int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, @@ -663,6 +665,18 @@ sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) { return hardwareBitmap; } +CREATE_BRIDGE3(copyGraphicBufferInto, RenderThread* thread, GraphicBuffer* buffer, SkBitmap* bitmap) { + return (void*) args->thread->readback().copyGraphicBufferInto(args->buffer, args->bitmap); +} + +int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { + SETUP_TASK(copyGraphicBufferInto); + args->thread = &RenderThread::getInstance(); + args->bitmap = bitmap; + args->buffer = buffer; + return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task))); +} + void RenderProxy::post(RenderTask* task) { mRenderThread.queue(task); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index e559142c1ace..44a5a147b6da 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -35,6 +35,8 @@ #include "DrawFrameTask.h" namespace android { +class GraphicBuffer; + namespace uirenderer { class DeferredLayerUpdater; @@ -131,6 +133,8 @@ public: ANDROID_API static void prepareToDraw(Bitmap& bitmap); static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap); + + static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap); private: RenderThread& mRenderThread; CanvasContext* mContext; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index f3789c8d8cbb..e13d0ce6d688 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -17,10 +17,13 @@ #include "RenderThread.h" #include "../renderstate/RenderState.h" +#include "../pipeline/skia/SkiaOpenGLReadback.h" #include "CanvasContext.h" #include "EglManager.h" +#include "OpenGLReadback.h" #include "RenderProxy.h" #include "VulkanManager.h" +#include "utils/FatVector.h" #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> @@ -196,6 +199,30 @@ void RenderThread::initThreadLocals() { mVkManager = new VulkanManager(*this); } +Readback& RenderThread::readback() { + + if (!mReadback) { + auto renderType = Properties::getRenderPipelineType(); + switch (renderType) { + case RenderPipelineType::OpenGL: + mReadback = new OpenGLReadbackImpl(*this); + break; + case RenderPipelineType::SkiaGL: + case RenderPipelineType::SkiaVulkan: + // It works to use the OpenGL pipeline for Vulkan but this is not + // ideal as it causes us to create an OpenGL context in addition + // to the Vulkan one. + mReadback = new skiapipeline::SkiaOpenGLReadback(*this); + break; + default: + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + break; + } + } + + return *mReadback; +} + int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE("Display event receiver pipe was closed or an error occurred. " @@ -285,10 +312,18 @@ bool RenderThread::threadLoop() { "RenderThread Looper POLL_ERROR!"); nsecs_t nextWakeup; - // Process our queue, if we have anything - while (RenderTask* task = nextTask(&nextWakeup)) { - task->run(); - // task may have deleted itself, do not reference it again + { + FatVector<RenderTask*, 10> workQueue; + // Process our queue, if we have anything. By first acquiring + // all the pending events then processing them we avoid vsync + // starvation if more tasks are queued while we are processing tasks. + while (RenderTask* task = nextTask(&nextWakeup)) { + workQueue.push_back(task); + } + for (auto task : workQueue) { + task->run(); + // task may have deleted itself, do not reference it again + } } if (nextWakeup == LLONG_MAX) { timeoutMillis = -1; diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 12050dd9c772..d121bcf5b084 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -37,6 +37,7 @@ class DisplayEventReceiver; namespace uirenderer { +class Readback; class RenderState; class TestUtils; @@ -93,6 +94,7 @@ public: RenderState& renderState() const { return *mRenderState; } EglManager& eglManager() const { return *mEglManager; } JankTracker& jankTracker() { return *mJankTracker; } + Readback& readback(); const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; } @@ -151,6 +153,7 @@ private: EglManager* mEglManager; JankTracker* mJankTracker = nullptr; + Readback* mReadback = nullptr; sk_sp<GrContext> mGrContext; VulkanManager* mVkManager; diff --git a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp new file mode 100644 index 000000000000..bc6fc6452e90 --- /dev/null +++ b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "TestSceneBase.h" + +class ReadbackFromHardware; + +static TestScene::Registrar _SaveLayer(TestScene::Info{ + "readbackFromHBitmap", + "Allocates hardware bitmap and readback data from it.", + TestScene::simpleCreateScene<ReadbackFromHardware> +}); + +class ReadbackFromHardware : public TestScene { +public: + static sk_sp<Bitmap> createHardwareBitmap() { + SkBitmap skBitmap; + SkImageInfo info = SkImageInfo::Make(400, 400, kN32_SkColorType, kPremul_SkAlphaType); + skBitmap.allocPixels(info); + skBitmap.eraseColor(Color::Red_500); + SkCanvas canvas(skBitmap); + SkPaint paint; + paint.setColor(Color::Blue_500); + canvas.drawRect(SkRect::MakeXYWH(30, 30, 30, 150), paint); + canvas.drawRect(SkRect::MakeXYWH(30, 30, 100, 30), paint); + canvas.drawRect(SkRect::MakeXYWH(30, 100, 70, 30), paint); + return Bitmap::allocateHardwareBitmap(skBitmap); + } + + void createContent(int width, int height, Canvas& canvas) override { + canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background + + sk_sp<Bitmap> hardwareBitmap(createHardwareBitmap()); + + SkBitmap readback; + hardwareBitmap->getSkBitmap(&readback); + + SkBitmap canvasBitmap; + sk_sp<Bitmap> heapBitmap(TestUtils::createBitmap(hardwareBitmap->width(), + hardwareBitmap->height(), &canvasBitmap)); + + SkCanvas skCanvas(canvasBitmap); + skCanvas.drawBitmap(readback, 0, 0); + canvas.drawBitmap(*heapBitmap, 0, 0, nullptr); + + canvas.drawBitmap(*hardwareBitmap, 0, 500, nullptr); + } + + void doFrame(int frameNr) override { } +}; diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index d77a082188f6..bbb7184664b6 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -2189,9 +2189,9 @@ public class ExifInterface { /** * Loads EXIF attributes from a JPEG input stream. * - * @param inputStream The input stream that starts with the JPEG data. + * @param in The input stream that starts with the JPEG data. * @param jpegOffset The offset value in input stream for JPEG data. - * @param imageTypes The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for + * @param imageType The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for * primary image, IFD_TYPE_PREVIEW for preview image, and * IFD_TYPE_THUMBNAIL for thumbnail image. * @throws IOException If the data contains invalid JPEG markers, offsets, or length values. diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 972fc738cb09..f176aac09856 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -863,4 +863,6 @@ <!-- Content description for drawer menu button [CHAR_LIMIT=30]--> <string name="content_description_menu_button">Menu</string> + <!-- Label for Greenwich mean time, used in a string like GMT+05:00. [CHAR LIMIT=NONE] --> + <string name="time_zone_gmt">GMT</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 9608daad70e9..24ede164fbdd 100755 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -116,6 +116,10 @@ public final class A2dpProfile implements LocalBluetoothProfile { List<BluetoothDevice> sinks = getConnectedDevices(); if (sinks != null) { for (BluetoothDevice sink : sinks) { + if (sink.equals(device)) { + Log.w(TAG, "Connecting to device " + device + " : disconnect skipped"); + continue; + } mService.disconnect(sink); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java index 857ca49eafc2..4bfca9b61d6b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java +++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java @@ -19,9 +19,13 @@ package com.android.settingslib.datetime; import android.content.Context; import android.content.res.XmlResourceParser; import android.icu.text.TimeZoneNames; -import android.text.BidiFormatter; -import android.text.TextDirectionHeuristics; +import android.support.v4.text.BidiFormatter; +import android.support.v4.text.TextDirectionHeuristicsCompat; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.format.DateUtils; +import android.text.style.TtsSpan; import android.util.Log; import android.view.View; @@ -29,7 +33,6 @@ import com.android.settingslib.R; import org.xmlpull.v1.XmlPullParserException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -65,28 +68,41 @@ public class ZoneGetter { private static final String TAG = "ZoneGetter"; public static final String KEY_ID = "id"; // value: String + + /** + * @deprecated Use {@link #KEY_DISPLAY_LABEL} instead. + */ + @Deprecated public static final String KEY_DISPLAYNAME = "name"; // value: String + + public static final String KEY_DISPLAY_LABEL = "display_label"; // value: CharSequence + + /** + * @deprecated Use {@link #KEY_OFFSET_LABEL} instead. + */ + @Deprecated public static final String KEY_GMT = "gmt"; // value: String public static final String KEY_OFFSET = "offset"; // value: int (Integer) + public static final String KEY_OFFSET_LABEL = "offset_label"; // value: CharSequence private static final String XMLTAG_TIMEZONE = "timezone"; - public static String getTimeZoneOffsetAndName(Context context, TimeZone tz, Date now) { + public static CharSequence getTimeZoneOffsetAndName(Context context, TimeZone tz, Date now) { final Locale locale = Locale.getDefault(); - final String gmtString = getGmtOffsetString(locale, tz, now); + final CharSequence gmtText = getGmtOffsetText(context, locale, tz, now); final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale); final ZoneGetterData data = new ZoneGetterData(context); final boolean useExemplarLocationForLocalNames = shouldUseExemplarLocationForLocalNames(data, timeZoneNames); - final String zoneNameString = getTimeZoneDisplayName(data, timeZoneNames, + final CharSequence zoneName = getTimeZoneDisplayName(data, timeZoneNames, useExemplarLocationForLocalNames, tz, tz.getID()); - if (zoneNameString == null) { - return gmtString; + if (zoneName == null) { + return gmtText; } // We don't use punctuation here to avoid having to worry about localizing that too! - return gmtString + " " + zoneNameString; + return TextUtils.concat(gmtText, " ", zoneName); } public static List<Map<String, Object>> getZonesList(Context context) { @@ -103,28 +119,30 @@ public class ZoneGetter { List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>(); for (int i = 0; i < data.zoneCount; i++) { TimeZone tz = data.timeZones[i]; - String gmtOffsetString = data.gmtOffsetStrings[i]; + CharSequence gmtOffsetText = data.gmtOffsetTexts[i]; - String displayName = getTimeZoneDisplayName(data, timeZoneNames, + CharSequence displayName = getTimeZoneDisplayName(data, timeZoneNames, useExemplarLocationForLocalNames, tz, data.olsonIdsToDisplay[i]); - if (displayName == null || displayName.isEmpty()) { - displayName = gmtOffsetString; + if (TextUtils.isEmpty(displayName)) { + displayName = gmtOffsetText; } int offsetMillis = tz.getOffset(now.getTime()); Map<String, Object> displayEntry = - createDisplayEntry(tz, gmtOffsetString, displayName, offsetMillis); + createDisplayEntry(tz, gmtOffsetText, displayName, offsetMillis); zones.add(displayEntry); } return zones; } private static Map<String, Object> createDisplayEntry( - TimeZone tz, String gmtOffsetString, String displayName, int offsetMillis) { - Map<String, Object> map = new HashMap<String, Object>(); + TimeZone tz, CharSequence gmtOffsetText, CharSequence displayName, int offsetMillis) { + Map<String, Object> map = new HashMap<>(); map.put(KEY_ID, tz.getID()); - map.put(KEY_DISPLAYNAME, displayName); - map.put(KEY_GMT, gmtOffsetString); + map.put(KEY_DISPLAYNAME, displayName.toString()); + map.put(KEY_DISPLAY_LABEL, displayName); + map.put(KEY_GMT, gmtOffsetText.toString()); + map.put(KEY_OFFSET_LABEL, gmtOffsetText); map.put(KEY_OFFSET, offsetMillis); return map; } @@ -162,15 +180,15 @@ public class ZoneGetter { private static boolean shouldUseExemplarLocationForLocalNames(ZoneGetterData data, TimeZoneNames timeZoneNames) { - final Set<String> localZoneNames = new HashSet<String>(); + final Set<CharSequence> localZoneNames = new HashSet<>(); final Date now = new Date(); for (int i = 0; i < data.zoneCount; i++) { final String olsonId = data.olsonIdsToDisplay[i]; if (data.localZoneIds.contains(olsonId)) { final TimeZone tz = data.timeZones[i]; - String displayName = getZoneLongName(timeZoneNames, tz, now); + CharSequence displayName = getZoneLongName(timeZoneNames, tz, now); if (displayName == null) { - displayName = data.gmtOffsetStrings[i]; + displayName = data.gmtOffsetTexts[i]; } final boolean nameIsUnique = localZoneNames.add(displayName); if (!nameIsUnique) { @@ -182,8 +200,9 @@ public class ZoneGetter { return false; } - private static String getTimeZoneDisplayName(ZoneGetterData data, TimeZoneNames timeZoneNames, - boolean useExemplarLocationForLocalNames, TimeZone tz, String olsonId) { + private static CharSequence getTimeZoneDisplayName(ZoneGetterData data, + TimeZoneNames timeZoneNames, boolean useExemplarLocationForLocalNames, TimeZone tz, + String olsonId) { final Date now = new Date(); final boolean isLocalZoneId = data.localZoneIds.contains(olsonId); final boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames; @@ -213,23 +232,70 @@ public class ZoneGetter { return names.getDisplayName(tz.getID(), nameType, now.getTime()); } - private static String getGmtOffsetString(Locale locale, TimeZone tz, Date now) { - // Use SimpleDateFormat to format the GMT+00:00 string. - final SimpleDateFormat gmtFormatter = new SimpleDateFormat("ZZZZ"); - gmtFormatter.setTimeZone(tz); - String gmtString = gmtFormatter.format(now); + private static void appendWithTtsSpan(SpannableStringBuilder builder, CharSequence content, + TtsSpan span) { + int start = builder.length(); + builder.append(content); + builder.setSpan(span, start, builder.length(), 0); + } + + private static String twoDigits(int input) { + StringBuilder builder = new StringBuilder(3); + if (input < 0) builder.append('-'); + String string = Integer.toString(Math.abs(input)); + if (string.length() == 1) builder.append("0"); + builder.append(string); + return builder.toString(); + } + + /** + * Get the GMT offset text label for the given time zone, in the format "GMT-08:00". This will + * also add TTS spans to give hints to the text-to-speech engine for the type of data it is. + * + * @param context The context which the string is displayed in. + * @param locale The locale which the string is displayed in. This should be the same as the + * locale of the context. + * @param tz Time zone to get the GMT offset from. + * @param now The current time, used to tell whether daylight savings is active. + * @return A CharSequence suitable for display as the offset label of {@code tz}. + */ + private static CharSequence getGmtOffsetText(Context context, Locale locale, TimeZone tz, + Date now) { + SpannableStringBuilder builder = new SpannableStringBuilder(); + + appendWithTtsSpan(builder, "GMT", + new TtsSpan.TextBuilder(context.getString(R.string.time_zone_gmt)).build()); + + int offsetMillis = tz.getOffset(now.getTime()); + if (offsetMillis >= 0) { + appendWithTtsSpan(builder, "+", new TtsSpan.VerbatimBuilder("+").build()); + } + + final int offsetHours = (int) (offsetMillis / DateUtils.HOUR_IN_MILLIS); + appendWithTtsSpan(builder, twoDigits(offsetHours), + new TtsSpan.MeasureBuilder().setNumber(offsetHours).setUnit("hour").build()); + + builder.append(":"); + + final int offsetMinutes = (int) (offsetMillis / DateUtils.MINUTE_IN_MILLIS); + final int offsetMinutesRemaining = Math.abs(offsetMinutes) % 60; + appendWithTtsSpan(builder, twoDigits(offsetMinutesRemaining), + new TtsSpan.MeasureBuilder().setNumber(offsetMinutesRemaining) + .setUnit("minute").build()); + + CharSequence gmtText = new SpannableString(builder); // Ensure that the "GMT+" stays with the "00:00" even if the digits are RTL. final BidiFormatter bidiFormatter = BidiFormatter.getInstance(); boolean isRtl = TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL; - gmtString = bidiFormatter.unicodeWrap(gmtString, - isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR); - return gmtString; + gmtText = bidiFormatter.unicodeWrap(gmtText, + isRtl ? TextDirectionHeuristicsCompat.RTL : TextDirectionHeuristicsCompat.LTR); + return gmtText; } private static final class ZoneGetterData { public final String[] olsonIdsToDisplay; - public final String[] gmtOffsetStrings; + public final CharSequence[] gmtOffsetTexts; public final TimeZone[] timeZones; public final Set<String> localZoneIds; public final int zoneCount; @@ -243,13 +309,13 @@ public class ZoneGetter { zoneCount = olsonIdsToDisplayList.size(); olsonIdsToDisplay = new String[zoneCount]; timeZones = new TimeZone[zoneCount]; - gmtOffsetStrings = new String[zoneCount]; + gmtOffsetTexts = new CharSequence[zoneCount]; for (int i = 0; i < zoneCount; i++) { final String olsonId = olsonIdsToDisplayList.get(i); olsonIdsToDisplay[i] = olsonId; final TimeZone tz = TimeZone.getTimeZone(olsonId); timeZones[i] = tz; - gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now); + gmtOffsetTexts[i] = getGmtOffsetText(context, locale, tz, now); } // Create a lookup of local zone IDs. diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java index e07856e46779..7e3f67b875e5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java @@ -39,6 +39,8 @@ public final class CategoryKey { public static final String CATEGORY_SYSTEM_INPUT = "com.android.settings.category.ia.input"; public static final String CATEGORY_SYSTEM_LANGUAGE = "com.android.settings.category.ia.language"; + public static final String CATEGORY_SYSTEM_DEVELOPMENT = + "com.android.settings.category.ia.development"; public static final Map<String, String> KEY_COMPAT_MAP; diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java index 14a0e820a69a..f3658c38ca35 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java @@ -20,6 +20,7 @@ import android.content.Context; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Pair; @@ -116,6 +117,7 @@ public class CategoryManager { } backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap); normalizePriority(context, mCategoryByKeyMap); + filterDuplicateTiles(mCategoryByKeyMap); } } @@ -185,6 +187,31 @@ public class CategoryManager { } /** + * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the + * same intent. + */ + @VisibleForTesting + synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) { + for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) { + final DashboardCategory category = categoryEntry.getValue(); + final int count = category.tiles.size(); + final Set<ComponentName> components = new ArraySet<>(); + for (int i = count - 1; i >= 0; i--) { + final Tile tile = category.tiles.get(i); + if (tile.intent == null) { + continue; + } + final ComponentName tileComponent = tile.intent.getComponent(); + if (components.contains(tileComponent)) { + category.tiles.remove(i); + } else { + components.add(tileComponent); + } + } + } + } + + /** * Normalize priority value for tiles within a single {@code DashboardCategory}. * * @see #normalizePriority(Context, Map) @@ -218,7 +245,6 @@ public class CategoryManager { continue; } dashboardCategory.tiles.get(i).priority = i; - } } } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java index 57e06ddb5c04..703e9d29e6ac 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java @@ -19,6 +19,9 @@ import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.support.test.filters.SmallTest; +import android.text.Spanned; +import android.text.style.TtsSpan; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,14 +58,41 @@ public class ZoneGetterTest { testTimeZoneOffsetAndNameInner(TIME_ZONE_LA_ID, "Pacific Daylight Time"); } + @Test + public void getZonesList_checkTypes() { + final List<Map<String, Object>> zones = + ZoneGetter.getZonesList(InstrumentationRegistry.getContext()); + for (Map<String, Object> zone : zones) { + assertTrue(zone.get(ZoneGetter.KEY_DISPLAYNAME) instanceof String); + assertTrue(zone.get(ZoneGetter.KEY_DISPLAY_LABEL) instanceof CharSequence); + assertTrue(zone.get(ZoneGetter.KEY_OFFSET) instanceof Integer); + assertTrue(zone.get(ZoneGetter.KEY_OFFSET_LABEL) instanceof CharSequence); + assertTrue(zone.get(ZoneGetter.KEY_ID) instanceof String); + assertTrue(zone.get(ZoneGetter.KEY_GMT) instanceof String); + } + } + + @Test + public void getTimeZoneOffsetAndName_withTtsSpan() { + final Context context = InstrumentationRegistry.getContext(); + final TimeZone timeZone = TimeZone.getTimeZone(TIME_ZONE_LA_ID); + + CharSequence timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone, + mCalendar.getTime()); + assertTrue("Time zone string should be spanned", timeZoneString instanceof Spanned); + assertTrue("Time zone display name should have TTS spans", + ((Spanned) timeZoneString).getSpans( + 0, timeZoneString.length(), TtsSpan.class).length > 0); + } + private void testTimeZoneOffsetAndNameInner(String timeZoneId, String expectedName) { final Context context = InstrumentationRegistry.getContext(); final TimeZone timeZone = TimeZone.getTimeZone(timeZoneId); - String timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone, + CharSequence timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone, mCalendar.getTime()); - assertTrue(timeZoneString.endsWith(expectedName)); + assertTrue(timeZoneString.toString().endsWith(expectedName)); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java index a0254cd94923..b209f4ec665a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java @@ -58,9 +58,10 @@ public class CategoryKeyTest { allKeys.add(CategoryKey.CATEGORY_SYSTEM); allKeys.add(CategoryKey.CATEGORY_SYSTEM_INPUT); allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE); + allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT); // DO NOT REMOVE ANYTHING ABOVE - assertThat(allKeys.size()).isEqualTo(13); + assertThat(allKeys.size()).isEqualTo(14); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java index 50bb216c9d39..573ec1f055fe 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java @@ -228,4 +228,60 @@ public class CategoryManagerTest { assertThat(category.tiles.get(1).priority).isEqualTo(100); assertThat(category.tiles.get(2).priority).isEqualTo(50); } + + @Test + public void filterTiles_noDuplicate_noChange() { + // Create some unique tiles + final String testPackage = + ShadowApplication.getInstance().getApplicationContext().getPackageName(); + final DashboardCategory category = new DashboardCategory(); + final Tile tile1 = new Tile(); + tile1.intent = + new Intent().setComponent(new ComponentName(testPackage, "class1")); + tile1.priority = 100; + final Tile tile2 = new Tile(); + tile2.intent = + new Intent().setComponent(new ComponentName(testPackage, "class2")); + tile2.priority = 100; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage, "class3")); + tile3.priority = 50; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap); + + assertThat(category.tiles.size()).isEqualTo(3); + } + + @Test + public void filterTiles_hasDuplicate_shouldOnlyKeepUniqueTiles() { + // Create tiles pointing to same intent. + final String testPackage = + ShadowApplication.getInstance().getApplicationContext().getPackageName(); + final DashboardCategory category = new DashboardCategory(); + final Tile tile1 = new Tile(); + tile1.intent = + new Intent().setComponent(new ComponentName(testPackage, "class1")); + tile1.priority = 100; + final Tile tile2 = new Tile(); + tile2.intent = + new Intent().setComponent(new ComponentName(testPackage, "class1")); + tile2.priority = 100; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage, "class1")); + tile3.priority = 50; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap); + + assertThat(category.tiles.size()).isEqualTo(1); + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index c633aa15c8e3..951b27f75aeb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -225,8 +225,10 @@ public class DozeMachine { boolean newPolicy = wakeLockPolicy(newState); if (mWakeLockHeldForCurrentState && !newPolicy) { mWakeLock.release(); + mWakeLockHeldForCurrentState = false; } else if (!mWakeLockHeldForCurrentState && newPolicy) { mWakeLock.acquire(); + mWakeLockHeldForCurrentState = true; } } diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index 5f27b74a8351..6d0e77c06132 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -62,8 +62,7 @@ public class FragmentHostManager { private void createFragmentHost(Parcelable savedState) { mFragments = FragmentController.createController(new HostCallbacks()); mFragments.attachHost(null); - // TODO: Remove non-staticness from FragmentLifecycleCallbacks (hopefully). - mLifecycleCallbacks = mFragments.getFragmentManager().new FragmentLifecycleCallbacks() { + mLifecycleCallbacks = new FragmentLifecycleCallbacks() { @Override public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 9b48e4d02623..5bfc17fcaaf9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -104,8 +104,8 @@ public class RecentsTaskLoadPlan { int currentUserId = UserHandle.USER_CURRENT; updateCurrentQuietProfilesCache(currentUserId); SystemServicesProxy ssp = Recents.getSystemServices(); - mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), - currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles); + mRawTasks = new ArrayList<>(ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), + currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles)); // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(mRawTasks); diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java index dd8075057e17..005206fcd14c 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java +++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java @@ -22,39 +22,93 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -public abstract class CurrentUserTracker extends BroadcastReceiver { +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; - private Context mContext; - private int mCurrentUserId; +public abstract class CurrentUserTracker { + private final UserReceiver mUserReceiver; + + private Consumer<Integer> mCallback = this::onUserSwitched; public CurrentUserTracker(Context context) { - mContext = context; + mUserReceiver = UserReceiver.getInstance(context); } public int getCurrentUserId() { - return mCurrentUserId; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { - int oldUserId = mCurrentUserId; - mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); - if (oldUserId != mCurrentUserId) { - onUserSwitched(mCurrentUserId); - } - } + return mUserReceiver.getCurrentUserId(); } public void startTracking() { - mCurrentUserId = ActivityManager.getCurrentUser(); - IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); - mContext.registerReceiver(this, filter); + mUserReceiver.addTracker(mCallback); } public void stopTracking() { - mContext.unregisterReceiver(this); + mUserReceiver.removeTracker(mCallback); } public abstract void onUserSwitched(int newUserId); + + private static class UserReceiver extends BroadcastReceiver { + private static UserReceiver sInstance; + + private Context mAppContext; + private boolean mReceiverRegistered; + private int mCurrentUserId; + + private List<Consumer<Integer>> mCallbacks = new ArrayList<>(); + + private UserReceiver(Context context) { + mAppContext = context.getApplicationContext(); + } + + static UserReceiver getInstance(Context context) { + if (sInstance == null) { + sInstance = new UserReceiver(context); + } + return sInstance; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { + notifyUserSwitched(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + } + } + + public int getCurrentUserId() { + return mCurrentUserId; + } + + private void addTracker(Consumer<Integer> callback) { + if (!mCallbacks.contains(callback)) { + mCallbacks.add(callback); + } + if (!mReceiverRegistered) { + mCurrentUserId = ActivityManager.getCurrentUser(); + IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); + mAppContext.registerReceiver(this, filter); + mReceiverRegistered = true; + } + } + + private void removeTracker(Consumer<Integer> callback) { + if (mCallbacks.contains(callback)) { + mCallbacks.remove(callback); + if (mCallbacks.size() == 0 && mReceiverRegistered) { + mAppContext.unregisterReceiver(this); + mReceiverRegistered = false; + } + } + } + + private void notifyUserSwitched(int newUserId) { + if (mCurrentUserId != newUserId) { + mCurrentUserId = newUserId; + for (Consumer<Integer> consumer : mCallbacks) { + consumer.accept(newUserId); + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 5696123dd756..621743365a6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -165,6 +165,14 @@ public class StatusBarWindowView extends FrameLayout { mBrightnessMirror = findViewById(R.id.brightness_mirror); } + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + if (child.getId() == R.id.brightness_mirror) { + mBrightnessMirror = child; + } + } + public void setService(PhoneStatusBar service) { mService = service; mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index ba7c923efe71..863f0e5a9897 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -189,6 +189,19 @@ public class DozeMachineTest { @Test @UiThreadTest + public void testWakeLock_releasedAfterPulse() { + mMachine.requestState(INITIALIZED); + + mMachine.requestState(DOZE); + mMachine.requestState(DOZE_REQUEST_PULSE); + mMachine.requestState(DOZE_PULSING); + mMachine.requestState(DOZE_PULSE_DONE); + + assertFalse(mWakeLockFake.isHeld()); + } + + @Test + @UiThreadTest public void testScreen_offInDoze() { mMachine.requestState(INITIALIZED); diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 9b4b1868cdbb..45f2ec76588a 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -2653,6 +2653,12 @@ message MetricsEvent { // OS: O ENTERPRISE_PRIVACY_SETTINGS = 628; + // ACTION: Longpress on a TextView. + // SUBTYPE: 1 is for START_SELECTION, 2 is for START_DRAG_AND_DROP, 0 is for OTHER. + // CATEGORY: TEXT_CONTROLS + // OS: O + TEXT_LONGPRESS = 629; + // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 67014314595f..f4ddc06d381c 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -249,13 +249,16 @@ public class LockSettingsService extends ILockSettings.Stub { try { randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40); String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed)); + tieProfileLockToParent(managedUserId, newPassword); setLockPasswordInternal(newPassword, managedUserPassword, managedUserId); // We store a private credential for the managed user that's unlocked by the primary // account holder's credential. As such, the user will never be prompted to enter this // password directly, so we always store a password. setLong(LockPatternUtils.PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId); - tieProfileLockToParent(managedUserId, newPassword); + } catch (KeyStoreException e) { + // Bug: 32490092 + Slog.e(TAG, "Not able to set keys to keystore", e); } catch (NoSuchAlgorithmException | RemoteException e) { Slog.e(TAG, "Fail to tie managed profile", e); // Nothing client can do to fix this issue, so we do not throw exception out @@ -776,6 +779,7 @@ public class LockSettingsService extends ILockSettings.Stub { } private void unlockChildProfile(int profileHandle) throws RemoteException { + if (DEBUG) Slog.v(TAG, "Unlock child profile"); try { doVerifyPassword(getDecryptedPasswordForTiedProfile(profileHandle), false, 0 /* no challenge */, profileHandle, null /* progressCallback */); @@ -1035,7 +1039,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private void tieProfileLockToParent(int userId, String password) { + private void tieProfileLockToParent(int userId, String password) throws KeyStoreException { if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId); byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8); byte[] encryptionResult; @@ -1077,7 +1081,7 @@ public class LockSettingsService extends ILockSettings.Stub { keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId); } } catch (CertificateException | UnrecoverableKeyException - | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException + | IOException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException("Failed to encrypt key", e); } @@ -1219,7 +1223,11 @@ public class LockSettingsService extends ILockSettings.Stub { } finally { if (managedUserId != -1 && managedUserDecryptedPassword != null) { if (DEBUG) Slog.v(TAG, "Restore tied profile lock"); - tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); + try { + tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); + } catch (KeyStoreException e) { + throw new RuntimeException("Failed to tie profile lock", e); + } } } } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index b5fecfb17aeb..8fd1d2f163ff 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1881,7 +1881,13 @@ public class AccountManagerService final long accountId = accounts.accountsDb.findDeAccountId(accountToRename); if (accountId >= 0) { accounts.accountsDb.renameCeAccount(accountId, newName); - accounts.accountsDb.renameDeAccount(accountId, newName, accountToRename.name); + if (accounts.accountsDb.renameDeAccount( + accountId, newName, accountToRename.name)) { + accounts.accountsDb.setTransactionSuccessful(); + } else { + Log.e(TAG, "renameAccount failed"); + return null; + } } } finally { accounts.accountsDb.endTransaction(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 77d36f256803..1437c8385d42 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6324,13 +6324,18 @@ public class ActivityManagerService extends IActivityManager.Stub removeLruProcessLocked(app); if (mBackupTarget != null && mBackupTarget.app.pid == pid) { Slog.w(TAG, "Unattached app died before backup, skipping"); - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentDisconnected(app.info.packageName); - } catch (RemoteException e) { - // Can't happen; the backup manager is local - } + mHandler.post(new Runnable() { + @Override + public void run(){ + try { + IBackupManager bm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + bm.agentDisconnected(app.info.packageName); + } catch (RemoteException e) { + // Can't happen; the backup manager is local + } + } + }); } if (isPendingBroadcastProcessLocked(pid)) { Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping"); @@ -13523,9 +13528,11 @@ public class ActivityManagerService extends IActivityManager.Stub final ProcessRecord r = handleApplicationWtfInner(callingUid, callingPid, app, tag, crashInfo); - if (r != null && r.pid != Process.myPid() && - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WTF_IS_FATAL, 0) != 0) { + final boolean isFatal = "eng".equals(Build.TYPE) || Settings.Global + .getInt(mContext.getContentResolver(), Settings.Global.WTF_IS_FATAL, 0) != 0; + final boolean isSystem = (r == null) || r.persistent; + + if (isFatal && !isSystem) { mAppErrors.crashApplication(r, crashInfo); return true; } else { @@ -16909,13 +16916,18 @@ public class ActivityManagerService extends IActivityManager.Stub if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) { if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App " + mBackupTarget.appInfo + " died during backup"); - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentDisconnected(app.info.packageName); - } catch (RemoteException e) { - // can't happen; backup manager is local - } + mHandler.post(new Runnable() { + @Override + public void run(){ + try { + IBackupManager bm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + bm.agentDisconnected(app.info.packageName); + } catch (RemoteException e) { + // can't happen; backup manager is local + } + } + }); } for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index ccd94cb475a3..dff7cefae456 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1524,8 +1524,8 @@ class ActivityStarter { private void updateTaskReturnToType( TaskRecord task, int launchFlags, ActivityStack focusedStack) { - if (focusedStack != null && focusedStack.isHomeStack() && - focusedStack.topTask().isOnTopLauncher()) { + if (focusedStack != null && focusedStack.isHomeStack() && focusedStack.topTask() != null + && focusedStack.topTask().isOnTopLauncher()) { // Since an on-top launcher will is moved to back when tasks are launched from it, // those tasks should first try to return to a non-home activity. // This also makes sure that non-home activities are visible under a transparent diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a530b3d6b39d..604b3ed85e25 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -80,10 +80,8 @@ import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; -import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioManagerInternal; -import android.media.AudioSystem; import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; @@ -243,7 +241,6 @@ public class NotificationManagerService extends SystemService { private int mDefaultNotificationLedOn; private int mDefaultNotificationLedOff; - private long[] mDefaultVibrationPattern; private long[] mFallbackVibrationPattern; private boolean mUseAttentionLight; @@ -304,7 +301,6 @@ public class NotificationManagerService extends SystemService { private RankingHandler mRankingHandler; private long mLastOverRateLogTime; private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; - private String mSystemNotificationSound; private SnoozeHelper mSnoozeHelper; private GroupHelper mGroupHelper; @@ -822,8 +818,6 @@ public class NotificationManagerService extends SystemService { private final class SettingsObserver extends ContentObserver { private final Uri NOTIFICATION_LIGHT_PULSE_URI = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); - private final Uri NOTIFICATION_SOUND_URI - = Settings.System.getUriFor(Settings.System.NOTIFICATION_SOUND); private final Uri NOTIFICATION_RATE_LIMIT_URI = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE); @@ -835,8 +829,6 @@ public class NotificationManagerService extends SystemService { ContentResolver resolver = getContext().getContentResolver(); resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(NOTIFICATION_SOUND_URI, - false, this, UserHandle.USER_ALL); resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, false, this, UserHandle.USER_ALL); update(null); @@ -860,10 +852,6 @@ public class NotificationManagerService extends SystemService { mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver, Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate); } - if (uri == null || NOTIFICATION_SOUND_URI.equals(uri)) { - mSystemNotificationSound = Settings.System.getString(resolver, - Settings.System.NOTIFICATION_SOUND); - } } } @@ -939,8 +927,8 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting - void setSystemNotificationSound(String systemNotificationSound) { - mSystemNotificationSound = systemNotificationSound; + void setFallbackVibrationPattern(long[] vibrationPattern) { + mFallbackVibrationPattern = vibrationPattern; } @Override @@ -1068,11 +1056,6 @@ public class NotificationManagerService extends SystemService { mDefaultNotificationLedOff = resources.getInteger( R.integer.config_defaultNotificationLedOff); - mDefaultVibrationPattern = getLongArray(resources, - R.array.config_defaultNotificationVibePattern, - VIBRATE_PATTERN_MAXLEN, - DEFAULT_VIBRATE_PATTERN); - mFallbackVibrationPattern = getLongArray(resources, R.array.config_notificationFallbackVibePattern, VIBRATE_PATTERN_MAXLEN, @@ -3034,43 +3017,17 @@ public class NotificationManagerService extends SystemService { && mAudioManager != null) { if (DBG) Slog.v(TAG, "Interrupting!"); - // should we use the default notification sound? (indicated either by - // DEFAULT_SOUND or because notification.sound is pointing at - // Settings.System.NOTIFICATION_SOUND) - final boolean useDefaultSound = - (notification.defaults & Notification.DEFAULT_SOUND) != 0 - || Settings.System.DEFAULT_NOTIFICATION_URI.equals(notification.sound); - - Uri soundUri = null; - if (useDefaultSound) { - soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; - - // check to see if the default notification sound is silent - hasValidSound = mSystemNotificationSound != null; - } else if (notification.sound != null) { - soundUri = notification.sound; - hasValidSound = (soundUri != null); - } else if (record.getChannel().getRingtone() != null) { - soundUri = record.getChannel().getRingtone(); - hasValidSound = (soundUri != null); - } - - // Does the notification want to specify its own vibration? - final boolean hasCustomVibrate = notification.vibrate != null; - - // new in 4.2: if there was supposed to be a sound and we're in vibrate - // mode, and no other vibration is specified, we fall back to vibration - final boolean convertSoundToVibration = - !hasCustomVibrate - && hasValidSound - && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE); - - // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. - final boolean useDefaultVibrate = - (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; - final boolean hasChannelVibration = record.getChannel().shouldVibrate(); - hasValidVibrate = useDefaultVibrate || convertSoundToVibration || - hasCustomVibrate || hasChannelVibration; + Uri soundUri = record.getSound(); + hasValidSound = (soundUri != null); + long[] vibration = record.getVibration(); + // Demote sound to vibration if vibration missing & phone in vibration mode. + if (vibration == null + && hasValidSound + && (mAudioManager.getRingerModeInternal() + == AudioManager.RINGER_MODE_VIBRATE)) { + vibration = mFallbackVibrationPattern; + } + hasValidVibrate = vibration != null; // We can alert, and we're allowed to alert, but if the developer asked us to only do // it once, and we already have, then don't. @@ -3078,54 +3035,17 @@ public class NotificationManagerService extends SystemService { && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) { sendAccessibilityEvent(notification, record.sbn.getPackageName()); - if (hasValidSound) { - boolean looping = - (notification.flags & Notification.FLAG_INSISTENT) != 0; - AudioAttributes audioAttributes = audioAttributesForNotification(notification); mSoundNotificationKey = key; - // do not play notifications if stream volume is 0 (typically because - // ringer mode is silent) or if there is a user of exclusive audio focus - if ((mAudioManager.getStreamVolume( - AudioAttributes.toLegacyStreamType(audioAttributes)) != 0) - && !mAudioManager.isAudioFocusExclusive()) { - final long identity = Binder.clearCallingIdentity(); - try { - final IRingtonePlayer player = - mAudioManager.getRingtonePlayer(); - if (player != null) { - if (DBG) Slog.v(TAG, "Playing sound " + soundUri - + " with attributes " + audioAttributes); - player.playAsync(soundUri, record.sbn.getUser(), looping, - audioAttributes); - beep = true; - } - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(identity); - } - } + beep = playSound(record, soundUri); } if (hasValidVibrate && !(mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT)) { mVibrateNotificationKey = key; - if (useDefaultVibrate || convertSoundToVibration) { - playNonCustomVibration(record, useDefaultVibrate); - } else if (notification.vibrate != null && notification.vibrate.length > 1) { - // If you want your own vibration pattern, you need the VIBRATE - // permission - mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), - notification.vibrate, - ((notification.flags & Notification.FLAG_INSISTENT) != 0) - ? 0: -1, audioAttributesForNotification(notification)); - buzz = true; - } else if (hasChannelVibration) { - playNonCustomVibration(record, useDefaultVibrate); - } + buzz = playVibration(record, vibration); } } - } // If a notification is updated to remove the actively playing sound or vibrate, // cancel that feedback now @@ -3168,41 +3088,42 @@ public class NotificationManagerService extends SystemService { || (record.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0; } - private boolean playNonCustomVibration(final NotificationRecord record, - boolean useDefaultVibrate) { + private boolean playSound(final NotificationRecord record, Uri soundUri) { + boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; + // do not play notifications if there is a user of exclusive audio focus + if (!mAudioManager.isAudioFocusExclusive()) { + final long identity = Binder.clearCallingIdentity(); + try { + final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); + if (player != null) { + if (DBG) Slog.v(TAG, "Playing sound " + soundUri + + " with attributes " + record.getAudioAttributes()); + player.playAsync(soundUri, record.sbn.getUser(), looping, + record.getAudioAttributes()); + return true; + } + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return false; + } + + private boolean playVibration(final NotificationRecord record, long[] vibration) { // Escalate privileges so we can use the vibrator even if the // notifying app does not have the VIBRATE permission. long identity = Binder.clearCallingIdentity(); try { - mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), - useDefaultVibrate ? mDefaultVibrationPattern - : mFallbackVibrationPattern, + mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), vibration, ((record.getNotification().flags & Notification.FLAG_INSISTENT) != 0) - ? 0: -1, audioAttributesForNotification(record.getNotification())); + ? 0: -1, record.getAudioAttributes()); return true; } finally{ Binder.restoreCallingIdentity(identity); } } - private static AudioAttributes audioAttributesForNotification(Notification n) { - if (n.audioAttributes != null - && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) { - // the audio attributes are set and different from the default, use them - return n.audioAttributes; - } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { - // the stream type is valid, use it - return new AudioAttributes.Builder() - .setInternalLegacyStreamType(n.audioStreamType) - .build(); - } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) { - return Notification.AUDIO_ATTRIBUTES_DEFAULT; - } else { - Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); - return Notification.AUDIO_ATTRIBUTES_DEFAULT; - } - } - void showNextToastLocked() { ToastRecord record = mToastQueue.get(0); while (record != null) { diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 5eacba668398..984fc38be25c 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -24,15 +24,21 @@ import static android.app.NotificationManager.IMPORTANCE_LOW; import android.app.Notification; import android.app.NotificationChannel; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.media.AudioAttributes; +import android.media.AudioSystem; +import android.net.Uri; +import android.os.Build; import android.os.UserHandle; +import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.Log; +import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.EventLogTags; @@ -100,6 +106,10 @@ public final class NotificationRecord { private int mSuppressedVisualEffects = 0; private String mUserExplanation; private String mPeopleExplanation; + private boolean mPreChannelsNotification = true; + private Uri mSound; + private long[] mVibration; + private AudioAttributes mAttributes; @VisibleForTesting public NotificationRecord(Context context, StatusBarNotification sbn) @@ -111,12 +121,95 @@ public final class NotificationRecord { mUpdateTimeMs = mCreationTimeMs; mContext = context; stats = new NotificationUsageStats.SingleNotificationStats(); - mImportance = defaultImportance(); + mPreChannelsNotification = isPreChannelsNotification(); + mSound = calculateSound(); + mVibration = calculateVibration(); + mAttributes = calculateAttributes(); + mImportance = calculateImportance(); } - private int defaultImportance() { + private boolean isPreChannelsNotification() { + try { + if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) { + final ApplicationInfo applicationInfo = + mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(), + 0, sbn.getUserId()); + if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) { + return true; + } + } + } catch (NameNotFoundException e) { + Slog.e(TAG, "Can't find package", e); + } + return false; + } + + private Uri calculateSound() { + final Notification n = sbn.getNotification(); + + Uri sound = sbn.getNotificationChannel().getSound(); + if (mPreChannelsNotification && (getChannel().getUserLockedFields() + & NotificationChannel.USER_LOCKED_SOUND) == 0) { + + final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0; + if (useDefaultSound) { + sound = Settings.System.DEFAULT_NOTIFICATION_URI; + } else if (n.sound != null) { + sound = n.sound; + } + } + return sound; + } + + private long[] calculateVibration() { + long[] vibration; + final long[] defaultVibration = NotificationManagerService.getLongArray( + mContext.getResources(), + com.android.internal.R.array.config_defaultNotificationVibePattern, + NotificationManagerService.VIBRATE_PATTERN_MAXLEN, + NotificationManagerService.DEFAULT_VIBRATE_PATTERN); + if (getChannel().shouldVibrate()) { + vibration = defaultVibration; + } else { + vibration = null; + } + if (mPreChannelsNotification + && (getChannel().getUserLockedFields() + & NotificationChannel.USER_LOCKED_VIBRATION) == 0) { + final Notification notification = sbn.getNotification(); + final boolean useDefaultVibrate = + (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; + if (useDefaultVibrate) { + vibration = defaultVibration; + } else { + vibration = notification.vibrate; + } + } + return vibration; + } + + private AudioAttributes calculateAttributes() { + final Notification n = sbn.getNotification(); + AudioAttributes attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; + + if (n.audioAttributes != null) { + // prefer audio attributes to stream type + attributes = n.audioAttributes; + } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { + // the stream type is valid, use it + attributes = new AudioAttributes.Builder() + .setInternalLegacyStreamType(n.audioStreamType) + .build(); + } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) { + Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); + } + return attributes; + } + + private int calculateImportance() { final Notification n = sbn.getNotification(); - int importance = IMPORTANCE_DEFAULT; + int importance = getChannel().getImportance(); + int requestedImportance = IMPORTANCE_DEFAULT; // Migrate notification flags to scores if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) { @@ -125,41 +218,39 @@ public final class NotificationRecord { switch (n.priority) { case Notification.PRIORITY_MIN: - importance = IMPORTANCE_MIN; + requestedImportance = IMPORTANCE_MIN; break; case Notification.PRIORITY_LOW: - importance = IMPORTANCE_LOW; + requestedImportance = IMPORTANCE_LOW; break; case Notification.PRIORITY_DEFAULT: - importance = IMPORTANCE_DEFAULT; + requestedImportance = IMPORTANCE_DEFAULT; break; case Notification.PRIORITY_HIGH: case Notification.PRIORITY_MAX: - importance = IMPORTANCE_HIGH; + requestedImportance = IMPORTANCE_HIGH; break; } - stats.requestedImportance = importance; - - boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0 - || (n.defaults & Notification.DEFAULT_VIBRATE) != 0 - || n.sound != null - || n.vibrate != null - || sbn.getNotificationChannel().shouldVibrate() - || sbn.getNotificationChannel().getRingtone() != null; - stats.isNoisy = isNoisy; - - if (!isNoisy && importance > IMPORTANCE_LOW) { - importance = IMPORTANCE_LOW; - } + stats.requestedImportance = requestedImportance; + stats.isNoisy = mSound != null || mVibration != null; + + if (mPreChannelsNotification + && (getChannel().getUserLockedFields() + & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0) { + if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) { + requestedImportance = IMPORTANCE_LOW; + } - if (isNoisy) { - if (importance < IMPORTANCE_DEFAULT) { - importance = IMPORTANCE_DEFAULT; + if (stats.isNoisy) { + if (requestedImportance < IMPORTANCE_DEFAULT) { + requestedImportance = IMPORTANCE_DEFAULT; + } } - } - if (n.fullScreenIntent != null) { - importance = IMPORTANCE_HIGH; + if (n.fullScreenIntent != null) { + requestedImportance = IMPORTANCE_HIGH; + } + importance = requestedImportance; } stats.naturalImportance = importance; @@ -284,6 +375,9 @@ public final class NotificationRecord { pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs); pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects); pw.println(prefix + " notificationChannel= " + notification.getChannel()); + pw.println(prefix + " mSound= " + mSound); + pw.println(prefix + " mVibration= " + mVibration); + pw.println(prefix + " mAttributes= " + mAttributes); } @@ -362,16 +456,16 @@ public final class NotificationRecord { private String getUserExplanation() { if (mUserExplanation == null) { - mUserExplanation = - mContext.getString(com.android.internal.R.string.importance_from_user); + mUserExplanation = mContext.getResources().getString( + com.android.internal.R.string.importance_from_user); } return mUserExplanation; } private String getPeopleExplanation() { if (mPeopleExplanation == null) { - mPeopleExplanation = - mContext.getString(com.android.internal.R.string.importance_from_person); + mPeopleExplanation = mContext.getResources().getString( + com.android.internal.R.string.importance_from_person); } return mPeopleExplanation; } @@ -533,4 +627,16 @@ public final class NotificationRecord { public NotificationChannel getChannel() { return sbn.getNotificationChannel(); } + + public Uri getSound() { + return mSound; + } + + public long[] getVibration() { + return mVibration; + } + + public AudioAttributes getAudioAttributes() { + return mAttributes; + } } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index d65ea7f7715b..90b3715c98c9 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -497,8 +497,8 @@ public class RankingHelper implements RankingConfig { if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_PRIORITY) == 0) { channel.setBypassDnd(updatedChannel.canBypassDnd()); } - if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_RINGTONE) == 0) { - channel.setRingtone(updatedChannel.getRingtone()); + if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_SOUND) == 0) { + channel.setSound(updatedChannel.getSound()); } if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_VIBRATION) == 0) { channel.setVibration(updatedChannel.shouldVibrate()); diff --git a/services/core/java/com/android/server/pm/EphemeralResolver.java b/services/core/java/com/android/server/pm/EphemeralResolver.java index 82f796daceb0..7ddd058b4e5a 100644 --- a/services/core/java/com/android/server/pm/EphemeralResolver.java +++ b/services/core/java/com/android/server/pm/EphemeralResolver.java @@ -39,6 +39,7 @@ import android.util.Slog; import com.android.server.pm.EphemeralResolverConnection.PhaseTwoCallback; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; @@ -72,19 +73,19 @@ public abstract class EphemeralResolver { EphemeralResolverConnection connection, EphemeralRequest requestObj, ActivityInfo ephemeralInstaller, Handler callbackHandler) { final Intent intent = requestObj.origIntent; - final EphemeralDigest digest = - new EphemeralDigest(intent.getData().getHost(), 5 /*maxDigests*/); - final int[] shaPrefix = digest.getDigestPrefix(); - final byte[][] digestBytes = digest.getDigestBytes(); + final String hostName = intent.getData().getHost(); + final EphemeralDigest digest = new EphemeralDigest(hostName, 5 /*maxDigests*/); final PhaseTwoCallback callback = new PhaseTwoCallback() { @Override - void onPhaseTwoResolved(List<EphemeralResolveInfo> ephemeralResolveInfoList, + void onPhaseTwoResolved(EphemeralResolveInfo ephemeralResolveInfo, int sequence) { final String packageName; final String splitName; - if (ephemeralResolveInfoList != null - && ephemeralResolveInfoList.size() > 0) { + if (ephemeralResolveInfo != null) { + final ArrayList<EphemeralResolveInfo> ephemeralResolveInfoList = + new ArrayList<EphemeralResolveInfo>(1); + ephemeralResolveInfoList.add(ephemeralResolveInfo); final EphemeralResponse ephemeralIntentInfo = EphemeralResolver.filterEphemeralIntent( ephemeralResolveInfoList, intent, null /*resolvedType*/, @@ -118,7 +119,7 @@ public abstract class EphemeralResolver { } }; connection.getEphemeralIntentFilterList( - shaPrefix, callback, callbackHandler, 0 /*sequence*/); + hostName, callback, callbackHandler, 0 /*sequence*/); } /** diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java index 20d9813e250a..2b6ce10741c4 100644 --- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java +++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java @@ -84,24 +84,24 @@ final class EphemeralResolverConnection { return null; } - public final void getEphemeralIntentFilterList(int digestPrefix[], PhaseTwoCallback callback, + public final void getEphemeralIntentFilterList(String hostName, PhaseTwoCallback callback, Handler callbackHandler, final int sequence) { final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() { @Override public void sendResult(Bundle data) throws RemoteException { - final ArrayList<EphemeralResolveInfo> ephemeralResolveInfoList = - data.getParcelableArrayList(EphemeralResolverService.EXTRA_RESOLVE_INFO); + final EphemeralResolveInfo ephemeralResolveInfo = + data.getParcelable(EphemeralResolverService.EXTRA_RESOLVE_INFO); callbackHandler.post(new Runnable() { @Override public void run() { - callback.onPhaseTwoResolved(ephemeralResolveInfoList, sequence); + callback.onPhaseTwoResolved(ephemeralResolveInfo, sequence); } }); } }; try { getRemoteInstanceLazy() - .getEphemeralIntentFilterList(remoteCallback, digestPrefix, sequence); + .getEphemeralIntentFilterList(remoteCallback, hostName, sequence); } catch (RemoteException re) { } catch (TimeoutException te) { } @@ -173,8 +173,7 @@ final class EphemeralResolverConnection { * Asynchronous callback when results come back from ephemeral resolution phase two. */ public abstract static class PhaseTwoCallback { - abstract void onPhaseTwoResolved(List<EphemeralResolveInfo> ephemeralResolveInfoList, - int sequence); + abstract void onPhaseTwoResolved(EphemeralResolveInfo ephemeralResolveInfo, int sequence); } private final class MyServiceConnection implements ServiceConnection { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 0844d48b8669..5d739d13c898 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -413,6 +413,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, voiceInteraction); mService.mOpeningApps.remove(this); + mService.mUnknownAppVisibilityController.appRemoved(this); waitingToShow = false; if (mService.mClosingApps.contains(this)) { delayed = true; diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java index 2f49c82fc5f9..8f4f09e7ae90 100644 --- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java +++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java @@ -16,8 +16,13 @@ package com.android.server.wm; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_UNKNOWN_APP_VISIBILITY; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + import android.annotation.NonNull; import android.util.ArrayMap; +import android.util.Slog; import com.android.server.wm.WindowManagerService.H; @@ -31,6 +36,8 @@ import java.io.PrintWriter; */ class UnknownAppVisibilityController { + private static final String TAG = TAG_WITH_CLASS_NAME ? "UnknownAppVisibility" : TAG_WM; + /** * We are currently waiting until the app is done resuming. */ @@ -78,6 +85,9 @@ class UnknownAppVisibilityController { } void appRemoved(@NonNull AppWindowToken appWindow) { + if (DEBUG_UNKNOWN_APP_VISIBILITY) { + Slog.d(TAG, "App removed appWindow=" + appWindow); + } mUnknownApps.remove(appWindow); } @@ -86,6 +96,9 @@ class UnknownAppVisibilityController { * it is resumed and relaid out to resolve the visibility. */ void notifyLaunched(@NonNull AppWindowToken appWindow) { + if (DEBUG_UNKNOWN_APP_VISIBILITY) { + Slog.d(TAG, "App launched appWindow=" + appWindow); + } mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RESUME); } @@ -95,6 +108,9 @@ class UnknownAppVisibilityController { void notifyAppResumedFinished(@NonNull AppWindowToken appWindow) { if (mUnknownApps.containsKey(appWindow) && mUnknownApps.get(appWindow) == UNKNOWN_STATE_WAITING_RESUME) { + if (DEBUG_UNKNOWN_APP_VISIBILITY) { + Slog.d(TAG, "App resume finished appWindow=" + appWindow); + } mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RELAYOUT); } } @@ -106,6 +122,9 @@ class UnknownAppVisibilityController { if (!mUnknownApps.containsKey(appWindow)) { return; } + if (DEBUG_UNKNOWN_APP_VISIBILITY) { + Slog.d(TAG, "App relayouted appWindow=" + appWindow); + } int state = mUnknownApps.get(appWindow); if (state == UNKNOWN_STATE_WAITING_RELAYOUT) { mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE); @@ -114,6 +133,9 @@ class UnknownAppVisibilityController { } private void notifyVisibilitiesUpdated() { + if (DEBUG_UNKNOWN_APP_VISIBILITY) { + Slog.d(TAG, "Visibility updated DONE"); + } boolean changed = false; for (int i = mUnknownApps.size() - 1; i >= 0; i--) { if (mUnknownApps.valueAt(i) == UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE) { diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index f11281e7692f..1b61fca5e25c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -73,6 +73,7 @@ public class WindowManagerDebugConfig { static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; static final boolean SHOW_STACK_CRAWLS = false; static final boolean DEBUG_WINDOW_CROP = false; + static final boolean DEBUG_UNKNOWN_APP_VISIBILITY = false; static final String TAG_KEEP_SCREEN_ON = "DebugKeepScreenOn"; static final boolean DEBUG_KEEP_SCREEN_ON = false; diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index c03a4602f2fe..4d43e8e9c368 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -67,7 +67,8 @@ LOCAL_SHARED_LIBRARIES += \ libEGL \ libGLESv2 \ libnetutils \ - libhidl \ + libhidlbase \ + libhidltransport \ libhwbinder \ libutils \ android.hardware.audio.common@2.0 \ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 543bba660ecc..c497cb1c4413 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -205,6 +205,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_AFFILIATION_ID = "affiliation-id"; + private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last-security-log-retrieval"; + + private static final String TAG_LAST_BUG_REPORT_REQUEST = "last-bug-report-request"; + + private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last-network-log-retrieval"; + private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending"; private static final String ATTR_VALUE = "value"; @@ -466,6 +472,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Set<String> mAffiliationIds = new ArraySet<>(); + long mLastSecurityLogRetrievalTime = -1; + + long mLastBugReportRequestTime = -1; + + long mLastNetworkLogsRetrievalTime = -1; + // Used for initialization of users created by createAndManageUsers. boolean mAdminBroadcastPending = false; PersistableBundle mInitBundle = null; @@ -2359,6 +2371,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, TAG_AFFILIATION_ID); } + if (policy.mLastSecurityLogRetrievalTime >= 0) { + out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); + out.attribute(null, ATTR_VALUE, + Long.toString(policy.mLastSecurityLogRetrievalTime)); + out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); + } + + if (policy.mLastBugReportRequestTime >= 0) { + out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST); + out.attribute(null, ATTR_VALUE, + Long.toString(policy.mLastBugReportRequestTime)); + out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST); + } + + if (policy.mLastNetworkLogsRetrievalTime >= 0) { + out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); + out.attribute(null, ATTR_VALUE, + Long.toString(policy.mLastNetworkLogsRetrievalTime)); + out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); + } + if (policy.mAdminBroadcastPending) { out.startTag(null, TAG_ADMIN_BROADCAST_PENDING); out.attribute(null, ATTR_VALUE, @@ -2515,6 +2548,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.doNotAskCredentialsOnBoot = true; } else if (TAG_AFFILIATION_ID.equals(tag)) { policy.mAffiliationIds.add(parser.getAttributeValue(null, "id")); + } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) { + policy.mLastSecurityLogRetrievalTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) { + policy.mLastBugReportRequestTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) { + policy.mLastNetworkLogsRetrievalTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { String pending = parser.getAttributeValue(null, ATTR_VALUE); policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); @@ -5521,9 +5563,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } + final long currentTime = System.currentTimeMillis(); + synchronized (this) { + DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); + if (currentTime > policyData.mLastBugReportRequestTime) { + policyData.mLastBugReportRequestTime = currentTime; + saveSettingsLocked(UserHandle.USER_SYSTEM); + } + } + final long callingIdentity = mInjector.binderClearCallingIdentity(); try { - ActivityManager.getService().requestBugReport( + mInjector.getIActivityManager().requestBugReport( ActivityManager.BUGREPORT_OPTION_REMOTE); mRemoteBugreportServiceIsActive.set(true); @@ -6530,6 +6581,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void enforceSystemUid() { + if (!isCallerWithSystemUid()) { + throw new SecurityException("Only the system can call this method."); + } + } + private void ensureCallerPackage(@Nullable String packageName) { if (packageName == null) { Preconditions.checkState(isCallerWithSystemUid(), @@ -8699,9 +8756,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Managed user cannot have a managed profile. return false; } + boolean canRemoveProfile + = !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER); final long ident = mInjector.binderClearCallingIdentity(); try { - if (!mUserManager.canAddMoreManagedProfiles(callingUserId, true)) { + if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) { return false; } } finally { @@ -9169,6 +9228,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private synchronized void recordSecurityLogRetrievalTime() { + final long currentTime = System.currentTimeMillis(); + DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); + if (currentTime > policyData.mLastSecurityLogRetrievalTime) { + policyData.mLastSecurityLogRetrievalTime = currentTime; + saveSettingsLocked(UserHandle.USER_SYSTEM); + } + } + @Override public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) { Preconditions.checkNotNull(admin); @@ -9178,6 +9246,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } + recordSecurityLogRetrievalTime(); + ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>(); try { SecurityLog.readPreviousEvents(output); @@ -9193,6 +9263,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(admin); ensureDeviceOwnerManagingSingleUser(admin); + recordSecurityLogRetrievalTime(); + List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs(); return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null; } @@ -9668,9 +9740,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (mNetworkLogger == null) { return null; } - return isNetworkLoggingEnabledInternalLocked() - ? mNetworkLogger.retrieveLogs(batchToken) - : null; + + if (!isNetworkLoggingEnabledInternalLocked()) { + return null; + } + + final long currentTime = System.currentTimeMillis(); + synchronized (this) { + DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); + if (currentTime > policyData.mLastNetworkLogsRetrievalTime) { + policyData.mLastNetworkLogsRetrievalTime = currentTime; + saveSettingsLocked(UserHandle.USER_SYSTEM); + } + } + + return mNetworkLogger.retrieveLogs(batchToken); } /** @@ -9714,4 +9798,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { rawIntent.setComponent(info.serviceInfo.getComponentName()); return rawIntent; } + + @Override + public long getLastSecurityLogRetrievalTime() { + enforceSystemUid(); + return getUserData(UserHandle.USER_SYSTEM).mLastSecurityLogRetrievalTime; + } + + @Override + public long getLastBugReportRequestTime() { + enforceSystemUid(); + return getUserData(UserHandle.USER_SYSTEM).mLastBugReportRequestTime; + } + + @Override + public long getLastNetworkLogRetrievalTime() { + enforceSystemUid(); + return getUserData(UserHandle.USER_SYSTEM).mLastNetworkLogsRetrievalTime; + } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 1202025751c7..ba23f219c106 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -52,6 +52,7 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.app.NightDisplayController; +import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BinderInternal; import com.android.internal.os.SamplingProfilerIntegration; import com.android.internal.os.ZygoteInit; @@ -275,7 +276,9 @@ public final class SystemServer { // Here we go! Slog.i(TAG, "Entered the Android system server!"); - EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis()); + int uptimeMillis = (int) SystemClock.uptimeMillis(); + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis); + MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis); // In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system @@ -364,6 +367,7 @@ public final class SystemServer { if (StrictMode.conditionallyEnableDebugLogging()) { Slog.i(TAG, "Enabled StrictMode for system server main thread."); } + MetricsLogger.histogram(null, "boot_system_server_ready", (int) SystemClock.uptimeMillis()); // Loop forever. Looper.loop(); @@ -492,13 +496,16 @@ public final class SystemServer { } // Start the package manager. + MetricsLogger.histogram(null, "boot_package_manager_init_start", + (int) SystemClock.uptimeMillis()); traceBeginAndSlog("StartPackageManagerService"); mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager(); traceEnd(); - + MetricsLogger.histogram(null, "boot_package_manager_init_ready", + (int) SystemClock.uptimeMillis()); // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename // A/B artifacts after boot, before anything else might touch/need them. // Note: this isn't needed during decryption (we don't have /data anyways). diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java index d20e351157cb..39c5238d137a 100644 --- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -15,6 +15,10 @@ */ package com.android.server.notification; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; + import com.android.server.lights.Light; import com.android.server.statusbar.StatusBarManagerInternal; @@ -37,7 +41,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; -import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.StatusBarNotification; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; @@ -75,7 +78,6 @@ public class BuzzBeepBlinkTest { private String mTag = null; private int mUid = 1000; private int mPid = 2000; - private int mScore = 10; private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); private static final long[] CUSTOM_VIBRATION = new long[] { @@ -86,6 +88,7 @@ public class BuzzBeepBlinkTest { private static final int CUSTOM_LIGHT_COLOR = Color.BLACK; private static final int CUSTOM_LIGHT_ON = 10000; private static final int CUSTOM_LIGHT_OFF = 10000; + private static final long[] FALLBACK_VIBRATION = new long[] {100, 100, 100}; @Before public void setUp() { @@ -104,7 +107,7 @@ public class BuzzBeepBlinkTest { mService.setStatusBarManager(mStatusBar); mService.setLights(mLight); mService.setScreenOn(false); - mService.setSystemNotificationSound("beep!"); + mService.setFallbackVibrationPattern(FALLBACK_VIBRATION); } // @@ -161,21 +164,14 @@ public class BuzzBeepBlinkTest { false /* noisy */, true /* buzzy*/, false /* lights */); } - private NotificationRecord getLightsNotification() { - return getNotificationRecord(mId, false /* insistent */, true /* once */, - false /* noisy */, true /* buzzy*/, true /* lights */); + private NotificationRecord getBuzzyBeepyNotification() { + return getNotificationRecord(mId, false /* insistent */, false /* once */, + true /* noisy */, true /* buzzy*/, false /* lights */); } - private NotificationRecord getCustomBuzzyOnceNotification() { + private NotificationRecord getLightsNotification() { return getNotificationRecord(mId, false /* insistent */, true /* once */, - false /* noisy */, true /* buzzy*/, false /* lights */, - false /* defaultVibration */, true /* defaultSound */, true /* defaultLights */); - } - - private NotificationRecord getCustomBeepyNotification() { - return getNotificationRecord(mId, false /* insistent */, false /* once */, - true /* noisy */, false /* buzzy*/, false /* lights */, - true /* defaultVibration */, false /* defaultSound */, true /* defaultLights */); + false /* noisy */, true /* buzzy*/, true /* lights */); } private NotificationRecord getCustomLightsNotification() { @@ -192,6 +188,8 @@ public class BuzzBeepBlinkTest { private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once, boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration, boolean defaultSound, boolean defaultLights) { + NotificationChannel channel = + new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_HIGH); final Builder builder = new Builder(getContext()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) @@ -202,8 +200,10 @@ public class BuzzBeepBlinkTest { if (noisy) { if (defaultSound) { defaults |= Notification.DEFAULT_SOUND; + channel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI); } else { builder.setSound(CUSTOM_SOUND); + channel.setSound(CUSTOM_SOUND); } } if (buzzy) { @@ -212,6 +212,7 @@ public class BuzzBeepBlinkTest { } else { builder.setVibrate(CUSTOM_VIBRATION); } + channel.setVibration(true); } if (lights) { if (defaultLights) { @@ -219,6 +220,7 @@ public class BuzzBeepBlinkTest { } else { builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF); } + channel.setLights(true); } builder.setDefaults(defaults); @@ -226,8 +228,7 @@ public class BuzzBeepBlinkTest { if (insistent) { n.flags |= Notification.FLAG_INSISTENT; } - NotificationChannel channel = - new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_HIGH); + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, id, mTag, mUid, mPid, n, mUser, null, System.currentTimeMillis()); NotificationRecord r = new NotificationRecord(getContext(), sbn); @@ -282,11 +283,6 @@ public class BuzzBeepBlinkTest { eq(0), (AudioAttributes) anyObject()); } - private void verifyCustomVibrate() { - verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(CUSTOM_VIBRATION), eq(-1), - (AudioAttributes) anyObject()); - } - private void verifyStopVibrate() { verify(mVibrator, times(1)).cancel(); } @@ -333,30 +329,6 @@ public class BuzzBeepBlinkTest { } @Test - public void testBeepFromChannel() throws Exception { - NotificationRecord r = getQuietNotification(); - r.getChannel().setRingtone(Settings.System.DEFAULT_NOTIFICATION_URI); - r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing"); - - mService.buzzBeepBlinkLocked(r); - - verifyBeepLooped(); - verifyNeverVibrate(); - } - - @Test - public void testVibrateFromChannel() throws Exception { - NotificationRecord r = getQuietNotification(); - r.getChannel().setVibration(true); - r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing"); - - mService.buzzBeepBlinkLocked(r); - - verifyNeverBeep(); - verifyVibrate(); - } - - @Test public void testLightsFromChannel() throws Exception { NotificationRecord r = getQuietNotification(); r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing"); @@ -377,26 +349,6 @@ public class BuzzBeepBlinkTest { } @Test - public void testChannelNoOverwriteCustomVibration() throws Exception { - NotificationRecord r = getCustomBuzzyOnceNotification(); - r.getChannel().setVibration(true); - - mService.buzzBeepBlinkLocked(r); - - verifyCustomVibrate(); - } - - @Test - public void testChannelNoOverwriteCustomBeep() throws Exception { - NotificationRecord r = getCustomBeepyNotification(); - r.getChannel().setRingtone(Settings.System.DEFAULT_RINGTONE_URI); - - mService.buzzBeepBlinkLocked(r); - - verifyCustomBeep(); - } - - @Test public void testChannelNoOverwriteCustomLights() throws Exception { NotificationRecord r = getCustomLightsNotification(); r.getChannel().setLights(true); @@ -542,22 +494,39 @@ public class BuzzBeepBlinkTest { } @Test + public void testNoDemoteSoundToVibrateIfVibrateGiven() throws Exception { + NotificationRecord r = getBuzzyBeepyNotification(); + assertTrue(r.getSound() != null); + + // the phone is quiet + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); + + mService.buzzBeepBlinkLocked(r); + + verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(r.getVibration()), + eq(-1), (AudioAttributes) anyObject()); + } + + @Test public void testDemoteSoundToVibrate() throws Exception { NotificationRecord r = getBeepyNotification(); + assertTrue(r.getSound() != null); + assertNull(r.getVibration()); // the phone is quiet - when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mService.buzzBeepBlinkLocked(r); - verifyNeverBeep(); - verifyVibrate(); + verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(FALLBACK_VIBRATION), + eq(-1), (AudioAttributes) anyObject()); } @Test - public void testDemoteInsistenteSoundToVibrate() throws Exception { + public void testDemoteInsistentSoundToVibrate() throws Exception { NotificationRecord r = getInsistentBeepyNotification(); + assertTrue(r.getSound() != null); + assertNull(r.getVibration()); // the phone is quiet when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0); @@ -677,6 +646,7 @@ public class BuzzBeepBlinkTest { // set up internal state mService.buzzBeepBlinkLocked(r); + verifyVibrate(); // quiet update should stop making noise mService.buzzBeepBlinkLocked(s); @@ -684,14 +654,14 @@ public class BuzzBeepBlinkTest { } @Test - public void testQuietOnceUpdateCancelsvibrate() throws Exception { + public void testQuietOnceUpdateCancelVibrate() throws Exception { NotificationRecord r = getBuzzyNotification(); NotificationRecord s = getQuietOnceNotification(); s.isUpdate = true; // set up internal state mService.buzzBeepBlinkLocked(r); - Mockito.reset(mVibrator); + verifyVibrate(); // stop making noise - this is a weird corner case, but quiet should override once mService.buzzBeepBlinkLocked(s); diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java new file mode 100644 index 000000000000..b8f38320f2be --- /dev/null +++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java @@ -0,0 +1,287 @@ +/* + * 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.notification; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.app.Notification; +import android.app.Notification.Builder; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.media.AudioAttributes; +import android.net.Uri; +import android.os.Build; +import android.os.UserHandle; +import android.provider.Settings; +import android.service.notification.StatusBarNotification; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; + + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class NotificationRecordTest { + + private final Context mMockContext = Mockito.mock(Context.class); + @Mock PackageManager mPm; + + private final String pkg = "com.android.server.notification"; + private final int uid = 0; + private final String pkg2 = "pkg2"; + private final int uid2 = 1111111; + private final int id1 = 1; + private final int id2 = 2; + private final String tag1 = "tag1"; + private final String tag2 = "tag2"; + private final String channelId = "channel"; + NotificationChannel channel = + new NotificationChannel(channelId, "test", NotificationManager.IMPORTANCE_DEFAULT); + NotificationChannel defaultChannel = + new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test", + NotificationManager.IMPORTANCE_UNSPECIFIED); + private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); + final ApplicationInfo legacy = new ApplicationInfo(); + final ApplicationInfo upgrade = new ApplicationInfo(); + + + private static final long[] CUSTOM_VIBRATION = new long[] { + 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, + 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, + 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 }; + private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI; + private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) + .build(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mMockContext.getResources()).thenReturn( + InstrumentationRegistry.getContext().getResources()); + when(mMockContext.getPackageManager()).thenReturn(mPm); + + legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; + upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; + try { + when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy); + when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade); + } catch (PackageManager.NameNotFoundException e) {} + } + + private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound, + boolean buzzy, boolean defaultVibration) { + when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade); + final Builder builder = new Builder(mMockContext) + .setContentTitle("foo") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setPriority(Notification.PRIORITY_HIGH); + + int defaults = 0; + if (noisy) { + if (defaultSound) { + defaults |= Notification.DEFAULT_SOUND; + } else { + builder.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES); + } + } + if (buzzy) { + if (defaultVibration) { + defaults |= Notification.DEFAULT_VIBRATE; + } else { + builder.setVibrate(CUSTOM_VIBRATION); + } + } + builder.setDefaults(defaults); + if (!preO) { + builder.setChannel(channelId); + } + + + Notification n = builder.build(); + if (preO) { + return new StatusBarNotification(pkg, pkg, defaultChannel, id1, tag1, uid, uid, n, + mUser, null, uid); + } else { + return new StatusBarNotification(pkg2, pkg2, channel, id2, tag2, uid2, uid2, n, + mUser, null, uid2); + } + } + + // + // Tests + // + + @Test + public void testSound_default_preUpgradeUsesNotification() throws Exception { + defaultChannel.setSound(null); + // pre upgrade, default sound. + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound()); + } + + @Test + public void testSound_custom_preUpgradeUsesNotification() throws Exception { + defaultChannel.setSound(null); + // pre upgrade, custom sound. + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(CUSTOM_SOUND, record.getSound()); + } + + @Test + public void testSound_default_userLocked_preUpgrade() throws Exception { + defaultChannel.setSound(CUSTOM_SOUND); + defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND); + // pre upgrade, default sound. + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(CUSTOM_SOUND, record.getSound()); + } + + @Test + public void testSound_default_upgradeUsesChannel() throws Exception { + channel.setSound(CUSTOM_SOUND); + // post upgrade, default sound. + StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(CUSTOM_SOUND, record.getSound()); + } + + @Test + public void testVibration_default_preUpgradeUsesNotification() throws Exception { + defaultChannel.setVibration(false); + // pre upgrade, default vibration. + StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertNotNull(record.getVibration()); + } + + @Test + public void testVibration_custom_preUpgradeUsesNotification() throws Exception { + defaultChannel.setVibration(false); + // pre upgrade, custom vibration. + StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(CUSTOM_VIBRATION, record.getVibration()); + } + + @Test + public void testVibration_custom_userLocked_preUpgrade() throws Exception { + defaultChannel.setVibration(true); + defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION); + // pre upgrade, custom vibration. + StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */, + false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration())); + } + + @Test + public void testVibration_custom_upgradeUsesChannel() throws Exception { + channel.setVibration(true); + // post upgrade, custom vibration. + StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */, + false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration())); + } + + @Test + public void testAudioAttributes_preUpgrade() throws Exception { + defaultChannel.setSound(null); + // pre upgrade, default sound. + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes()); + } + + @Test + public void testAudioAttributes_upgrade() throws Exception { + channel.setSound(null); + // post upgrade, default sound. + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes()); + } + + @Test + public void testImportance_preUpgrade() throws Exception { + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance()); + } + + @Test + public void testImportance_locked_preUpgrade() throws Exception { + defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW); + defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); + StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance()); + } + + @Test + public void testImportance_upgrade() throws Exception { + StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn); + assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance()); + } +} diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java index 92c67b5b0aa9..3df0d66baebf 100644 --- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java @@ -52,7 +52,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; @@ -225,7 +224,7 @@ public class RankingHelperTest { new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel2 = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW); - channel2.setRingtone(new Uri.Builder().scheme("test").build()); + channel2.setSound(new Uri.Builder().scheme("test").build()); channel2.setLights(true); channel2.setBypassDnd(true); channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); @@ -441,15 +440,15 @@ public class RankingHelperTest { // all fields locked by user final NotificationChannel channel = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW); - channel.setRingtone(new Uri.Builder().scheme("test").build()); - channel.lockFields(NotificationChannel.USER_LOCKED_RINGTONE); + channel.setSound(new Uri.Builder().scheme("test").build()); + channel.lockFields(NotificationChannel.USER_LOCKED_SOUND); mHelper.createNotificationChannel(pkg, uid, channel); // same id, try to update all fields final NotificationChannel channel2 = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); - channel2.setRingtone(new Uri.Builder().scheme("test2").build()); + channel2.setSound(new Uri.Builder().scheme("test2").build()); mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); @@ -462,7 +461,7 @@ public class RankingHelperTest { // no fields locked by user final NotificationChannel channel = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW); - channel.setRingtone(new Uri.Builder().scheme("test").build()); + channel.setSound(new Uri.Builder().scheme("test").build()); channel.setLights(true); channel.setBypassDnd(true); channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); @@ -472,7 +471,7 @@ public class RankingHelperTest { // same id, try to update all fields final NotificationChannel channel2 = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); - channel2.setRingtone(new Uri.Builder().scheme("test2").build()); + channel2.setSound(new Uri.Builder().scheme("test2").build()); channel2.setLights(false); channel2.setBypassDnd(false); channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 80be62b3f2a2..4927f0ca873d 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -22,6 +22,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManagerInternal; import android.database.ContentObserver; import android.media.IAudioService; +import android.net.IIpConnectivityMetrics; import android.net.Uri; import android.os.Looper; import android.os.PowerManagerInternal; @@ -153,6 +154,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + IIpConnectivityMetrics getIIpConnectivityMetrics() { + return context.iipConnectivityMetrics; + } + + @Override IWindowManager getIWindowManager() { return context.iwindowManager; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 56ff6214a908..e55cafb6730b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -25,6 +25,9 @@ import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.Color; +import android.net.IIpConnectivityMetrics; import android.net.wifi.WifiInfo; import android.os.Build.VERSION_CODES; import android.os.Bundle; @@ -38,6 +41,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; import android.util.Pair; +import com.android.internal.R; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -53,6 +57,7 @@ import java.util.Set; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; @@ -2178,6 +2183,26 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); } + public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser() + throws Exception { + setDeviceOwner(); + + when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) + .thenReturn(true); + when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true); + when(mContext.userManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)) + .thenReturn(true); + when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, + false /* we can't remove a managed profile*/)).thenReturn(false); + when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, + true)).thenReturn(true); + setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE); + + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); + } + public void testForceUpdateUserSetupComplete_permission() { // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted try { @@ -2248,6 +2273,150 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertFalse(dpms.hasUserSetupCompleted()); } + private long getLastSecurityLogRetrievalTime() { + final long ident = mContext.binder.clearCallingIdentity(); + final long lastSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); + mContext.binder.restoreCallingIdentity(ident); + return lastSecurityLogRetrievalTime; + } + + public void testGetLastSecurityLogRetrievalTime() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + when(mContext.userManager.getUserCount()).thenReturn(1); + when(mContext.resources.getBoolean(R.bool.config_supportPreRebootSecurityLogs)) + .thenReturn(true); + + // No logs were retrieved so far. + assertEquals(-1, getLastSecurityLogRetrievalTime()); + + // Enabling logging should not change the timestamp. + dpm.setSecurityLoggingEnabled(admin1, true); + assertEquals(-1, getLastSecurityLogRetrievalTime()); + + // Retrieving the logs should update the timestamp. + final long beforeRetrieval = System.currentTimeMillis(); + dpm.retrieveSecurityLogs(admin1); + final long firstSecurityLogRetrievalTime = getLastSecurityLogRetrievalTime(); + final long afterRetrieval = System.currentTimeMillis(); + assertTrue(firstSecurityLogRetrievalTime >= beforeRetrieval); + assertTrue(firstSecurityLogRetrievalTime <= afterRetrieval); + + // Retrieving the pre-boot logs should update the timestamp. + Thread.sleep(2); + dpm.retrievePreRebootSecurityLogs(admin1); + final long secondSecurityLogRetrievalTime = getLastSecurityLogRetrievalTime(); + assertTrue(secondSecurityLogRetrievalTime > firstSecurityLogRetrievalTime); + + // Checking the timestamp again should not change it. + Thread.sleep(2); + assertEquals(secondSecurityLogRetrievalTime, getLastSecurityLogRetrievalTime()); + + // Retrieving the logs again should update the timestamp. + dpm.retrieveSecurityLogs(admin1); + final long thirdSecurityLogRetrievalTime = getLastSecurityLogRetrievalTime(); + assertTrue(thirdSecurityLogRetrievalTime > secondSecurityLogRetrievalTime); + + // Disabling logging should not change the timestamp. + Thread.sleep(2); + dpm.setSecurityLoggingEnabled(admin1, false); + assertEquals(thirdSecurityLogRetrievalTime, getLastSecurityLogRetrievalTime()); + + // Restarting the DPMS should not lose the timestamp. + initializeDpms(); + assertEquals(thirdSecurityLogRetrievalTime, getLastSecurityLogRetrievalTime()); + } + + private long getLastBugReportRequestTime() { + final long ident = mContext.binder.clearCallingIdentity(); + final long lastBugRequestTime = dpm.getLastBugReportRequestTime(); + mContext.binder.restoreCallingIdentity(ident); + return lastBugRequestTime; + } + + public void testGetLastBugReportRequestTime() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + when(mContext.userManager.getUserCount()).thenReturn(1); + mContext.packageName = admin1.getPackageName(); + mContext.applicationInfo = new ApplicationInfo(); + when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject())) + .thenReturn(Color.WHITE); + when(mContext.resources.getColor(eq(R.color.notification_material_background_color), + anyObject())).thenReturn(Color.WHITE); + + // No bug reports were requested so far. + assertEquals(-1, getLastSecurityLogRetrievalTime()); + + // Requesting a bug report should update the timestamp. + final long beforeRequest = System.currentTimeMillis(); + dpm.requestBugreport(admin1); + final long bugReportRequestTime = getLastBugReportRequestTime(); + final long afterRequest = System.currentTimeMillis(); + assertTrue(bugReportRequestTime >= beforeRequest); + assertTrue(bugReportRequestTime <= afterRequest); + + // Checking the timestamp again should not change it. + Thread.sleep(2); + assertEquals(bugReportRequestTime, getLastBugReportRequestTime()); + + // Restarting the DPMS should not lose the timestamp. + initializeDpms(); + assertEquals(bugReportRequestTime, getLastBugReportRequestTime()); + } + + private long getLastNetworkLogRetrievalTime() { + final long ident = mContext.binder.clearCallingIdentity(); + final long lastNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); + mContext.binder.restoreCallingIdentity(ident); + return lastNetworkLogRetrievalTime; + } + + public void testGetLastNetworkLogRetrievalTime() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + when(mContext.userManager.getUserCount()).thenReturn(1); + when(mContext.iipConnectivityMetrics.registerNetdEventCallback(anyObject())) + .thenReturn(true); + + // No logs were retrieved so far. + assertEquals(-1, getLastNetworkLogRetrievalTime()); + + // Attempting to retrieve logs without enabling logging should not change the timestamp. + dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); + assertEquals(-1, getLastNetworkLogRetrievalTime()); + + // Enabling logging should not change the timestamp. + dpm.setNetworkLoggingEnabled(admin1, true); + assertEquals(-1, getLastNetworkLogRetrievalTime()); + + // Retrieving the logs should update the timestamp. + final long beforeRetrieval = System.currentTimeMillis(); + dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); + final long firstNetworkLogRetrievalTime = getLastNetworkLogRetrievalTime(); + final long afterRetrieval = System.currentTimeMillis(); + assertTrue(firstNetworkLogRetrievalTime >= beforeRetrieval); + assertTrue(firstNetworkLogRetrievalTime <= afterRetrieval); + + // Checking the timestamp again should not change it. + Thread.sleep(2); + assertEquals(firstNetworkLogRetrievalTime, getLastNetworkLogRetrievalTime()); + + // Retrieving the logs again should update the timestamp. + dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); + final long secondNetworkLogRetrievalTime = getLastNetworkLogRetrievalTime(); + assertTrue(secondNetworkLogRetrievalTime > firstNetworkLogRetrievalTime); + + // Disabling logging should not change the timestamp. + Thread.sleep(2); + dpm.setNetworkLoggingEnabled(admin1, false); + assertEquals(secondNetworkLogRetrievalTime, getLastNetworkLogRetrievalTime()); + + // Restarting the DPMS should not lose the timestamp. + initializeDpms(); + assertEquals(secondNetworkLogRetrievalTime, getLastNetworkLogRetrievalTime()); + } + private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) { when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, userhandle)).thenReturn(isUserSetupComplete ? 1 : 0); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 37430ad5dfac..d74c6dc21c63 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -26,11 +26,14 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; +import android.content.res.Resources; import android.media.IAudioService; +import android.net.IIpConnectivityMetrics; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; @@ -249,6 +252,7 @@ public class DpmMockContext extends MockContext { public final MockBinder binder; public final EnvironmentForMock environment; + public final Resources resources; public final SystemPropertiesForMock systemProperties; public final UserManager userManager; public final UserManagerInternal userManagerInternal; @@ -257,6 +261,7 @@ public class DpmMockContext extends MockContext { public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; public final NotificationManager notificationManager; + public final IIpConnectivityMetrics iipConnectivityMetrics; public final IWindowManager iwindowManager; public final IActivityManager iactivityManager; public final IPackageManager ipackageManager; @@ -278,6 +283,10 @@ public class DpmMockContext extends MockContext { public final BuildMock buildMock = new BuildMock(); + public String packageName = null; + + public ApplicationInfo applicationInfo = null; + public DpmMockContext(Context context, File dataDir) { realTestContext = context; @@ -286,7 +295,8 @@ public class DpmMockContext extends MockContext { binder = new MockBinder(); environment = mock(EnvironmentForMock.class); - systemProperties= mock(SystemPropertiesForMock.class); + resources = mock(Resources.class); + systemProperties = mock(SystemPropertiesForMock.class); userManager = mock(UserManager.class); userManagerInternal = mock(UserManagerInternal.class); userManagerForMock = mock(UserManagerForMock.class); @@ -294,6 +304,7 @@ public class DpmMockContext extends MockContext { powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); notificationManager = mock(NotificationManager.class); + iipConnectivityMetrics = mock(IIpConnectivityMetrics.class); iwindowManager = mock(IWindowManager.class); iactivityManager = mock(IActivityManager.class); ipackageManager = mock(IPackageManager.class); @@ -416,6 +427,32 @@ public class DpmMockContext extends MockContext { } @Override + public Resources getResources() { + return resources; + } + + @Override + public Resources.Theme getTheme() { + return spiedContext.getTheme(); + } + + @Override + public String getPackageName() { + if (packageName != null) { + return packageName; + } + return super.getPackageName(); + } + + @Override + public ApplicationInfo getApplicationInfo() { + if (applicationInfo != null) { + return applicationInfo; + } + return super.getApplicationInfo(); + } + + @Override public Object getSystemService(String name) { switch (name) { case Context.USER_SERVICE: @@ -615,4 +652,9 @@ public class DpmMockContext extends MockContext { public ContentResolver getContentResolver() { return contentResolver; } + + @Override + public int getUserId() { + return UserHandle.getUserId(binder.getCallingUid()); + } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 3daa87c07564..0544fae6dee6 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -362,11 +362,6 @@ public class UsbDeviceManager { UsbManager.removeFunction(persisted, UsbManager.USB_FUNCTION_MTP)); } - String buildType = SystemProperties.get(BUILD_TYPE_PROPERTY); - if (buildType.equals(BUILD_TYPE_USERDEBUG) || buildType.equals(BUILD_TYPE_ENG)) { - setAdbEnabled(true); - } - setEnabledFunctions(null, false, false); String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); @@ -483,7 +478,7 @@ public class UsbDeviceManager { SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction); // Remove mtp from the config if file transfer is not enabled - if (oldFunctions.equals(UsbManager.USB_FUNCTION_MTP) && + if (oldFunctions.equals(UsbManager.USB_FUNCTION_MTP) && !mUsbDataUnlocked && enable) { oldFunctions = UsbManager.USB_FUNCTION_NONE; } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 016490cb50f7..c2a0ff14c7d3 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -515,9 +515,12 @@ public abstract class ConnectionService extends Service { final boolean isUnknown = args.argi2 == 1; if (!mAreAccountsInitialized) { Log.d(this, "Enqueueing pre-init request %s", id); - mPreInitializationConnectionRequests.add(new Runnable() { + mPreInitializationConnectionRequests.add( + new android.telecom.Logging.Runnable( + SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR", + null /*lock*/) { @Override - public void run() { + public void loggedRun() { createConnection( connectionManagerPhoneAccount, id, @@ -525,7 +528,7 @@ public abstract class ConnectionService extends Service { isIncoming, isUnknown); } - }); + }.prepare()); } else { createConnection( connectionManagerPhoneAccount, @@ -1381,9 +1384,9 @@ public abstract class ConnectionService extends Service { public void onResult( final List<ComponentName> componentNames, final List<IBinder> services) { - mHandler.post(new Runnable() { + mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oR", null /*lock*/) { @Override - public void run() { + public void loggedRun() { for (int i = 0; i < componentNames.size() && i < services.size(); i++) { mRemoteConnectionManager.addConnectionService( componentNames.get(i), @@ -1392,17 +1395,17 @@ public abstract class ConnectionService extends Service { onAccountsInitialized(); Log.d(this, "remote connection services found: " + services); } - }); + }.prepare()); } @Override public void onError() { - mHandler.post(new Runnable() { + mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oE", null /*lock*/) { @Override - public void run() { + public void loggedRun() { mAreAccountsInitialized = true; } - }); + }.prepare()); } }); } diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 446bbbb69996..ced6627e8d34 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -48,13 +48,13 @@ public class Log { // Generic tag for all Telecom logging @VisibleForTesting public static String TAG = "TelecomFramework"; + public static boolean DEBUG = isLoggable(android.util.Log.DEBUG); + public static boolean INFO = isLoggable(android.util.Log.INFO); + public static boolean VERBOSE = isLoggable(android.util.Log.VERBOSE); + public static boolean WARN = isLoggable(android.util.Log.WARN); + public static boolean ERROR = isLoggable(android.util.Log.ERROR); private static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */ - public static final boolean DEBUG = isLoggable(android.util.Log.DEBUG); - public static final boolean INFO = isLoggable(android.util.Log.INFO); - public static final boolean VERBOSE = isLoggable(android.util.Log.VERBOSE); - public static final boolean WARN = isLoggable(android.util.Log.WARN); - public static final boolean ERROR = isLoggable(android.util.Log.ERROR); // Used to synchronize singleton logging lazy initialization private static final Object sSingletonSync = new Object(); @@ -340,6 +340,11 @@ public class Log { public static void setTag(String tag) { TAG = tag; + DEBUG = isLoggable(android.util.Log.DEBUG); + INFO = isLoggable(android.util.Log.INFO); + VERBOSE = isLoggable(android.util.Log.VERBOSE); + WARN = isLoggable(android.util.Log.WARN); + ERROR = isLoggable(android.util.Log.ERROR); } /** diff --git a/telecomm/java/android/telecom/Logging/Runnable.java b/telecomm/java/android/telecom/Logging/Runnable.java index b2cf3a38360a..6e810538cc62 100644 --- a/telecomm/java/android/telecom/Logging/Runnable.java +++ b/telecomm/java/android/telecom/Logging/Runnable.java @@ -96,4 +96,4 @@ public abstract class Runnable { */ abstract public void loggedRun(); -} +}
\ No newline at end of file diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java index 3a7b8c09203a..c45bd6b04145 100644 --- a/telecomm/java/android/telecom/Logging/Session.java +++ b/telecomm/java/android/telecom/Logging/Session.java @@ -19,6 +19,7 @@ package android.telecom.Logging; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import android.telecom.Log; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; @@ -26,20 +27,23 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; /** - * The session that stores information about a thread's point of entry into the Telecom code that - * persists until the thread exits Telecom. + * Stores information about a thread's point of entry into that should persist until that thread + * exits. * @hide */ public class Session { public static final String START_SESSION = "START_SESSION"; + public static final String START_EXTERNAL_SESSION = "START_EXTERNAL_SESSION"; public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION"; public static final String CONTINUE_SUBSESSION = "CONTINUE_SUBSESSION"; public static final String END_SUBSESSION = "END_SUBSESSION"; public static final String END_SESSION = "END_SESSION"; public static final String SUBSESSION_SEPARATION_CHAR = "->"; + public static final String SESSION_SEPARATION_CHAR_CHILD = "_"; public static final String EXTERNAL_INDICATOR = "E-"; + public static final String TRUNCATE_STRING = "..."; /** * Initial value of mExecutionEndTimeMs and the final value of {@link #getLocalExecutionTime()} @@ -49,15 +53,19 @@ public class Session { public static class Info implements Parcelable { public final String sessionId; - public final String shortMethodName; + public final String methodPath; - private Info(String id, String methodName) { + private Info(String id, String path) { sessionId = id; - shortMethodName = methodName; + methodPath = path; } public static Info getInfo (Session s) { - return new Info(s.getFullSessionId(), s.getShortMethodName()); + // Create Info based on the truncated method path if the session is external, so we do + // not get multiple stacking external sessions (unless we have DEBUG level logging or + // lower). + return new Info(s.getFullSessionId(), s.getFullMethodPath( + !Log.DEBUG && s.isSessionExternal())); } /** Responsible for creating Info objects for deserialized Parcels. */ @@ -86,7 +94,7 @@ public class Session { @Override public void writeToParcel(Parcel destination, int flags) { destination.writeString(sessionId); - destination.writeString(shortMethodName); + destination.writeString(methodPath); } } @@ -226,7 +234,15 @@ public class Session { if (parentSession == null) { return mSessionId; } else { - return parentSession.getFullSessionId() + "_" + mSessionId; + if (Log.VERBOSE) { + return parentSession.getFullSessionId() + + // Append "_X" to subsession to show subsession designation. + SESSION_SEPARATION_CHAR_CHILD + mSessionId; + } else { + // Only worry about the base ID at the top of the tree. + return parentSession.getFullSessionId(); + } + } } @@ -259,16 +275,18 @@ public class Session { } // Recursively concatenate mShortMethodName with the parent Sessions to create full method - // path. Caches this string so that multiple calls for the path will be quick. - public String getFullMethodPath() { + // path. if truncatePath is set to true, all other external sessions (except for the most + // recent) will be truncated to "..." + public String getFullMethodPath(boolean truncatePath) { StringBuilder sb = new StringBuilder(); - getFullMethodPath(sb); + getFullMethodPath(sb, truncatePath); return sb.toString(); } - private synchronized void getFullMethodPath(StringBuilder sb) { - // Don't calculate if we have already figured it out! - if (!TextUtils.isEmpty(mFullMethodPathCache)) { + private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath) { + // Return cached value for method path. When returning the truncated path, recalculate the + // full path without using the cached value. + if (!TextUtils.isEmpty(mFullMethodPathCache) && !truncatePath) { sb.append(mFullMethodPathCache); return; } @@ -278,25 +296,37 @@ public class Session { // Check to see if the session has been renamed yet. If it has not, then the session // has not been continued. isSessionStarted = !mShortMethodName.equals(parentSession.mShortMethodName); - parentSession.getFullMethodPath(sb); + parentSession.getFullMethodPath(sb, truncatePath); sb.append(SUBSESSION_SEPARATION_CHAR); } // Encapsulate the external session's method name so it is obvious what part of the session - // is external. + // is external or truncate it if we do not want the entire history. if (isExternal()) { - sb.append("("); - sb.append(mShortMethodName); - sb.append(")"); + if (truncatePath) { + sb.append(TRUNCATE_STRING); + } else { + sb.append("("); + sb.append(mShortMethodName); + sb.append(")"); + } } else { sb.append(mShortMethodName); } - - if(isSessionStarted) { + // If we are returning the truncated path, do not save that path as the full path. + if (isSessionStarted && !truncatePath) { // Cache this value so that we do not have to do this work next time! // We do not cache the value if the session being evaluated hasn't been continued yet. mFullMethodPathCache = sb.toString(); } } + // Recursively move to the top of the tree to see if the parent session is external. + private boolean isSessionExternal() { + if (getParentSession() == null) { + return isExternal(); + } else { + return getParentSession().isSessionExternal(); + } + } @Override public int hashCode() { @@ -350,7 +380,7 @@ public class Session { return mParentSession.toString(); } else { StringBuilder methodName = new StringBuilder(); - methodName.append(getFullMethodPath()); + methodName.append(getFullMethodPath(false /*truncatePath*/)); if (mOwnerInfo != null && !mOwnerInfo.isEmpty()) { methodName.append("(InCall package: "); methodName.append(mOwnerInfo); diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java index 8ced7f8181c5..949f7b7a89ae 100644 --- a/telecomm/java/android/telecom/Logging/SessionManager.java +++ b/telecomm/java/android/telecom/Logging/SessionManager.java @@ -177,8 +177,9 @@ public class SessionManager { } // Create Session from Info and add to the sessionMapper under this ID. + Log.d(LOGGING_TAG, Session.START_EXTERNAL_SESSION); Session externalSession = new Session(Session.EXTERNAL_INDICATOR + sessionInfo.sessionId, - sessionInfo.shortMethodName, System.currentTimeMillis(), + sessionInfo.methodPath, System.currentTimeMillis(), false /*isStartedFromActiveSession*/, null); externalSession.setIsExternal(true); // Mark the external session as already completed, since we have no way of knowing when @@ -190,8 +191,6 @@ public class SessionManager { // Create a subsession from this external Session parent node Session childSession = createSubsession(); continueSession(childSession, shortMethodName); - - Log.d(LOGGING_TAG, Session.START_SESSION); } /** diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 60a27bd16633..1f06283304ca 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -312,6 +312,13 @@ public class CarrierConfigManager { */ public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string"; + /** + * Flag indicating whether we should downgrade/terminate VT calls and disable VT when + * data enabled changed (e.g. reach data limit or turn off data). + * @hide + */ + public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = + "ignore_data_enabled_changed_for_video_calls"; /** * Flag specifying whether WFC over IMS should be available for carrier: independent of @@ -1108,6 +1115,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true); sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, ""); + sDefaults.putBoolean(KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, false); sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false); diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index e87cba137483..c484fd31c467 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -20,6 +20,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Rlog; +import android.util.Log; import android.content.res.Resources; /** @@ -51,11 +52,6 @@ public class SignalStrength implements Parcelable { //Use int max, as -1 is a valid value in signal strength public static final int INVALID = 0x7FFFFFFF; - private static final int RSRP_THRESH_TYPE_STRICT = 0; - private static final int[] RSRP_THRESH_STRICT = new int[] {-140, -115, -105, -95, -85, -44}; - private static final int[] RSRP_THRESH_LENIENT = new int[] {-140, -128, -118, -108, -98, -44}; - - private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5 private int mGsmBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 private int mCdmaDbm; // This value is the RSSI value @@ -791,22 +787,20 @@ public class SignalStrength implements Parcelable { */ int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1; - int rsrpThreshType = Resources.getSystem().getInteger(com.android.internal.R.integer. - config_LTE_RSRP_threshold_type); - int[] threshRsrp; - if (rsrpThreshType == RSRP_THRESH_TYPE_STRICT) { - threshRsrp = RSRP_THRESH_STRICT; + int[] threshRsrp = Resources.getSystem().getIntArray( + com.android.internal.R.array.config_lteDbmThresholds); + if (threshRsrp.length != 6) { + Log.wtf(LOG_TAG, "getLteLevel - config_lteDbmThresholds has invalid num of elements." + + " Cannot evaluate RSRP signal."); } else { - threshRsrp = RSRP_THRESH_LENIENT; + if (mLteRsrp > threshRsrp[5]) rsrpIconLevel = -1; + else if (mLteRsrp >= threshRsrp[4]) rsrpIconLevel = SIGNAL_STRENGTH_GREAT; + else if (mLteRsrp >= threshRsrp[3]) rsrpIconLevel = SIGNAL_STRENGTH_GOOD; + else if (mLteRsrp >= threshRsrp[2]) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE; + else if (mLteRsrp >= threshRsrp[1]) rsrpIconLevel = SIGNAL_STRENGTH_POOR; + else if (mLteRsrp >= threshRsrp[0]) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } - if (mLteRsrp > threshRsrp[5]) rsrpIconLevel = -1; - else if (mLteRsrp >= threshRsrp[4]) rsrpIconLevel = SIGNAL_STRENGTH_GREAT; - else if (mLteRsrp >= threshRsrp[3]) rsrpIconLevel = SIGNAL_STRENGTH_GOOD; - else if (mLteRsrp >= threshRsrp[2]) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE; - else if (mLteRsrp >= threshRsrp[1]) rsrpIconLevel = SIGNAL_STRENGTH_POOR; - else if (mLteRsrp >= threshRsrp[0]) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - /* * Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5 * dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 330dbab5bab3..fee3aa508810 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -316,6 +316,12 @@ public class MockPackageManager extends PackageManager { /** @hide */ @Override + public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override public List<EphemeralApplicationInfo> getEphemeralApplications() { throw new UnsupportedOperationException(); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index b3ed9e1a0164..0b169bd474c6 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -272,6 +272,11 @@ public class BridgePackageManager extends PackageManager { } @Override + public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) { + return null; + } + + @Override public List<EphemeralApplicationInfo> getEphemeralApplications() { return null; } diff --git a/wifi/java/android/net/wifi/EAPConstants.java b/wifi/java/android/net/wifi/EAPConstants.java new file mode 100644 index 000000000000..b5f7c946ff05 --- /dev/null +++ b/wifi/java/android/net/wifi/EAPConstants.java @@ -0,0 +1,57 @@ +/** + * 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.net.wifi; + +/** + * Utility class containing EAP (Extensible Authentication Protocol) Related constants. + * + * @hide + */ +public final class EAPConstants { + // Constant definition for EAP types. Refer to + // http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml for more info. + public static final int EAP_MD5 = 4; + public static final int EAP_OTP = 5; + public static final int EAP_RSA = 9; + public static final int EAP_KEA = 11; + public static final int EAP_KEA_VALIDATE = 12; + public static final int EAP_TLS = 13; + public static final int EAP_LEAP = 17; + public static final int EAP_SIM = 18; + public static final int EAP_TTLS = 21; + public static final int EAP_AKA = 23; + public static final int EAP_3Com = 24; + public static final int EAP_MSCHAPv2 = 26; + public static final int EAP_PEAP = 29; + public static final int EAP_POTP = 32; + public static final int EAP_ActiontecWireless = 35; + public static final int EAP_HTTPDigest = 38; + public static final int EAP_SPEKE = 41; + public static final int EAP_MOBAC = 42; + public static final int EAP_FAST = 43; + public static final int EAP_ZLXEAP = 44; + public static final int EAP_Link = 45; + public static final int EAP_PAX = 46; + public static final int EAP_PSK = 47; + public static final int EAP_SAKE = 48; + public static final int EAP_IKEv2 = 49; + public static final int EAP_AKA_PRIME = 50; + public static final int EAP_GPSK = 51; + public static final int EAP_PWD = 52; + public static final int EAP_EKE = 53; + public static final int EAP_TEAP = 55; +} diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 465addfc1469..da8713555889 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -66,6 +66,93 @@ public class ScanResult implements Parcelable { * supported by the access point. */ public String capabilities; + + /** + * @hide + * No security protocol. + */ + public static final int PROTOCOL_NONE = 0; + /** + * @hide + * Security protocol type: WPA version 1. + */ + public static final int PROTOCOL_WPA = 1; + /** + * @hide + * Security protocol type: WPA version 2, also called RSN. + */ + public static final int PROTOCOL_WPA2 = 2; + /** + * @hide + * Security protocol type: + * OSU Server-only authenticated layer 2 Encryption Network. + * Used for Hotspot 2.0. + */ + public static final int PROTOCOL_OSEN = 3; + + /** + * @hide + * No security key management scheme. + */ + public static final int KEY_MGMT_NONE = 0; + /** + * @hide + * Security key management scheme: PSK. + */ + public static final int KEY_MGMT_PSK = 1; + /** + * @hide + * Security key management scheme: EAP. + */ + public static final int KEY_MGMT_EAP = 2; + /** + * @hide + * Security key management scheme: FT_PSK. + */ + public static final int KEY_MGMT_FT_PSK = 3; + /** + * @hide + * Security key management scheme: FT_EAP. + */ + public static final int KEY_MGMT_FT_EAP = 4; + /** + * @hide + * Security key management scheme: PSK_SHA256 + */ + public static final int KEY_MGMT_PSK_SHA256 = 5; + /** + * @hide + * Security key management scheme: EAP_SHA256. + */ + public static final int KEY_MGMT_EAP_SHA256 = 6; + /** + * @hide + * Security key management scheme: OSEN. + * Used for Hotspot 2.0. + */ + public static final int KEY_MGMT_OSEN = 7; + + /** + * @hide + * No cipher suite. + */ + public static final int CIPHER_NONE = 0; + /** + * @hide + * No group addressed, only used for group data cipher. + */ + public static final int CIPHER_NO_GROUP_ADDRESSED = 1; + /** + * @hide + * Cipher suite: TKIP + */ + public static final int CIPHER_TKIP = 2; + /** + * @hide + * Cipher suite: CCMP + */ + public static final int CIPHER_CCMP = 3; + /** * The detected signal level in dBm, also known as the RSSI. * diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 18aae534d098..a62a0fb582f1 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -61,6 +61,21 @@ public final class PasspointConfiguration implements Parcelable { credential.equals(that.credential)); } + /** + * Validate the configuration data. + * + * @return true on success or false on failure + */ + public boolean validate() { + if (homeSp == null || !homeSp.validate()) { + return false; + } + if (credential == null || !credential.validate()) { + return false; + } + return true; + } + public static final Creator<PasspointConfiguration> CREATOR = new Creator<PasspointConfiguration>() { @Override diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index 92dbd8afb2d3..57e65eb7a190 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -16,15 +16,21 @@ package android.net.wifi.hotspot2.pps; +import android.net.wifi.EAPConstants; import android.net.wifi.ParcelUtil; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; +import android.util.Log; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; /** * Class representing Credential subtree in the PerProviderSubscription (PPS) @@ -40,6 +46,14 @@ import java.util.Arrays; * @hide */ public final class Credential implements Parcelable { + private static final String TAG = "Credential"; + + /** + * Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2 + * Technical Specification Section 9.1 for more info. + */ + private static final int MAX_REALM_LENGTH = 253; + /** * The realm associated with this credential. It will be used to determine * if this credential can be used to authenticate with a given hotspot by @@ -53,6 +67,26 @@ public final class Credential implements Parcelable { */ public static final class UserCredential implements Parcelable { /** + * Maximum string length for username. Refer to Credential/UsernamePassword/Username + * node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info. + */ + private static final int MAX_USERNAME_LENGTH = 63; + + /** + * Maximum string length for password. Refer to Credential/UsernamePassword/Password + * in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info. + */ + private static final int MAX_PASSWORD_LENGTH = 255; + + /** + * Supported Non-EAP inner methods. Refer to + * Credential/UsernamePassword/EAPMethod/InnerEAPType in Hotspot 2.0 Release 2 Technical + * Specification Section 9.1 for more info. + */ + private static final Set<String> SUPPORTED_AUTH = + new HashSet<String>(Arrays.asList("PAP", "CHAP", "MS-CHAP", "MS-CHAP-V2")); + + /** * Username of the credential. */ public String username = null; @@ -104,6 +138,44 @@ public final class Credential implements Parcelable { TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod); } + /** + * Validate the configuration data. + * + * @return true on success or false on failure + */ + public boolean validate() { + if (TextUtils.isEmpty(username)) { + Log.d(TAG, "Missing username"); + return false; + } + if (username.length() > MAX_USERNAME_LENGTH) { + Log.d(TAG, "username exceeding maximum length: " + username.length()); + return false; + } + + if (TextUtils.isEmpty(password)) { + Log.d(TAG, "Missing password"); + return false; + } + if (password.length() > MAX_PASSWORD_LENGTH) { + Log.d(TAG, "password exceeding maximum length: " + password.length()); + return false; + } + + // Only supports EAP-TTLS for user credential. + if (eapType != EAPConstants.EAP_TTLS) { + Log.d(TAG, "Invalid EAP Type for user credential: " + eapType); + return false; + } + + // Verify Non-EAP inner method for EAP-TTLS. + if (!SUPPORTED_AUTH.contains(nonEapInnerMethod)) { + Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + nonEapInnerMethod); + return false; + } + return true; + } + public static final Creator<UserCredential> CREATOR = new Creator<UserCredential>() { @Override @@ -125,12 +197,22 @@ public final class Credential implements Parcelable { public UserCredential userCredential = null; /** - * Certificate based credential. + * Certificate based credential. This is used for EAP-TLS. * Contains fields under PerProviderSubscription/Credential/DigitalCertificate subtree. */ public static final class CertificateCredential implements Parcelable { /** - * Certificate type. Valid values are "802.1ar" and "x509v3". + * Supported certificate types. + */ + private static final String CERT_TYPE_X509V3 = "x509v3"; + + /** + * Certificate SHA-256 fingerprint length. + */ + private static final int CERT_SHA256_FINGER_PRINT_LENGTH = 32; + + /** + * Certificate type. */ public String certType = null; @@ -164,6 +246,24 @@ public final class Credential implements Parcelable { Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint); } + /** + * Validate the configuration data. + * + * @return true on success or false on failure + */ + public boolean validate() { + if (!TextUtils.equals(CERT_TYPE_X509V3, certType)) { + Log.d(TAG, "Unsupported certificate type: " + certType); + return false; + } + if (certSha256FingerPrint == null || + certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) { + Log.d(TAG, "Invalid SHA-256 fingerprint"); + return false; + } + return true; + } + public static final Creator<CertificateCredential> CREATOR = new Creator<CertificateCredential>() { @Override @@ -188,7 +288,14 @@ public final class Credential implements Parcelable { */ public static final class SimCredential implements Parcelable { /** - * International Mobile device Subscriber Identity. + * Maximum string length for IMSI. + */ + public static final int MAX_IMSI_LENGTH = 15; + + /** + * International Mobile Subscriber Identity, is used to identify the user + * of a cellular network and is a unique identification associated with all + * cellular networks */ public String imsi = null; @@ -225,6 +332,26 @@ public final class Credential implements Parcelable { dest.writeInt(eapType); } + /** + * Validate the configuration data. + * + * @return true on success or false on failure + */ + public boolean validate() { + // Note: this only validate the format of IMSI string itself. Additional verification + // will be done by WifiService at the time of provisioning to verify against the IMSI + // of the SIM card installed in the device. + if (!verifyImsi()) { + return false; + } + if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA && + eapType != EAPConstants.EAP_AKA_PRIME) { + Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType); + return false; + } + return true; + } + public static final Creator<SimCredential> CREATOR = new Creator<SimCredential>() { @Override @@ -240,6 +367,43 @@ public final class Credential implements Parcelable { return new SimCredential[size]; } }; + + /** + * Verify the IMSI (International Mobile Subscriber Identity) string. The string + * should contain zero or more numeric digits, and might ends with a "*" for prefix + * matching. + * + * @return true if IMSI is valid, false otherwise. + */ + private boolean verifyImsi() { + if (TextUtils.isEmpty(imsi)) { + Log.d(TAG, "Missing IMSI"); + return false; + } + if (imsi.length() > MAX_IMSI_LENGTH) { + Log.d(TAG, "IMSI exceeding maximum length: " + imsi.length()); + return false; + } + + // Locate the first non-digit character. + int nonDigit; + char stopChar = '\0'; + for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) { + stopChar = imsi.charAt(nonDigit); + if (stopChar < '0' || stopChar > '9') { + break; + } + } + + if (nonDigit == imsi.length()) { + return true; + } + else if (nonDigit == imsi.length()-1 && stopChar == '*') { + // Prefix matching. + return true; + } + return false; + } } public SimCredential simCredential = null; @@ -296,6 +460,42 @@ public final class Credential implements Parcelable { isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey); } + /** + * Validate the configuration data. + * + * @return true on success or false on failure + */ + public boolean validate() { + if (TextUtils.isEmpty(realm)) { + Log.d(TAG, "Missing realm"); + return false; + } + if (realm.length() > MAX_REALM_LENGTH) { + Log.d(TAG, "realm exceeding maximum length: " + realm.length()); + return false; + } + + // Verify the credential. + if (userCredential != null) { + if (!verifyUserCredential()) { + return false; + } + } else if (certCredential != null) { + if (!verifyCertCredential()) { + return false; + } + } else if (simCredential != null) { + if (!verifySimCredential()) { + return false; + } + } else { + Log.d(TAG, "Missing required credential"); + return false; + } + + return true; + } + public static final Creator<Credential> CREATOR = new Creator<Credential>() { @Override @@ -317,6 +517,91 @@ public final class Credential implements Parcelable { } }; + /** + * Verify user credential. + * + * @return true if user credential is valid, false otherwise. + */ + private boolean verifyUserCredential() { + if (userCredential == null) { + Log.d(TAG, "Missing user credential"); + return false; + } + if (certCredential != null || simCredential != null) { + Log.d(TAG, "Contained more than one type of credential"); + return false; + } + if (!userCredential.validate()) { + return false; + } + if (caCertificate == null) { + Log.d(TAG, "Missing CA Certificate for user credential"); + return false; + } + return true; + } + + /** + * Verify certificate credential, which is used for EAP-TLS. This will verify + * that the necessary client key and certificates are provided. + * + * @return true if certificate credential is valid, false otherwise. + */ + private boolean verifyCertCredential() { + if (certCredential == null) { + Log.d(TAG, "Missing certificate credential"); + return false; + } + if (userCredential != null || simCredential != null) { + Log.d(TAG, "Contained more than one type of credential"); + return false; + } + + if (!certCredential.validate()) { + return false; + } + + // Verify required key and certificates for certificate credential. + if (caCertificate == null) { + Log.d(TAG, "Missing CA Certificate for certificate credential"); + return false; + } + if (clientPrivateKey == null) { + Log.d(TAG, "Missing client private key for certificate credential"); + return false; + } + try { + // Verify SHA-256 fingerprint for client certificate. + if (!verifySha256Fingerprint(clientCertificateChain, + certCredential.certSha256FingerPrint)) { + Log.d(TAG, "SHA-256 fingerprint mismatch"); + return false; + } + } catch (NoSuchAlgorithmException | CertificateEncodingException e) { + Log.d(TAG, "Failed to verify SHA-256 fingerprint: " + e.getMessage()); + return false; + } + + return true; + } + + /** + * Verify SIM credential. + * + * @return true if SIM credential is valid, false otherwise. + */ + private boolean verifySimCredential() { + if (simCredential == null) { + Log.d(TAG, "Missing SIM credential"); + return false; + } + if (userCredential != null || certCredential != null) { + Log.d(TAG, "Contained more than one type of credential"); + return false; + } + return simCredential.validate(); + } + private static boolean isPrivateKeyEquals(PrivateKey key1, PrivateKey key2) { if (key1 == null && key2 == null) { return true; @@ -373,4 +658,31 @@ public final class Credential implements Parcelable { return true; } + + /** + * Verify that the digest for a certificate in the certificate chain matches expected + * fingerprint. The certificate that matches the fingerprint is the client certificate. + * + * @param certChain Chain of certificates + * @param expectedFingerprint The expected SHA-256 digest of the client certificate + * @return true if the certificate chain contains a matching certificate, false otherwise + * @throws NoSuchAlgorithmException + * @throws CertificateEncodingException + */ + private static boolean verifySha256Fingerprint(X509Certificate[] certChain, + byte[] expectedFingerprint) + throws NoSuchAlgorithmException, CertificateEncodingException { + if (certChain == null) { + return false; + } + MessageDigest digester = MessageDigest.getInstance("SHA-256"); + for (X509Certificate certificate : certChain) { + digester.reset(); + byte[] fingerprint = digester.digest(certificate.getEncoded()); + if (Arrays.equals(expectedFingerprint, fingerprint)) { + return true; + } + } + return false; + } } diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java index 2acc8bec8007..5837c06499e3 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java @@ -19,6 +19,7 @@ package android.net.wifi.hotspot2.pps; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; +import android.util.Log; import java.util.Arrays; @@ -34,6 +35,8 @@ import java.util.Arrays; * @hide */ public final class HomeSP implements Parcelable { + private static final String TAG = "HomeSP"; + /** * FQDN (Fully Qualified Domain Name) of this home service provider. */ @@ -77,6 +80,23 @@ public final class HomeSP implements Parcelable { Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs); } + /** + * Validate HomeSP data. + * + * @return true on success or false on failure + */ + public boolean validate() { + if (TextUtils.isEmpty(fqdn)) { + Log.d(TAG, "Missing FQDN"); + return false; + } + if (TextUtils.isEmpty(friendlyName)) { + Log.d(TAG, "Missing friendly name"); + return false; + } + return true; + } + public static final Creator<HomeSP> CREATOR = new Creator<HomeSP>() { @Override diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index be11f0ee64c0..b4a3acf08975 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -16,8 +16,10 @@ package android.net.wifi.hotspot2; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.net.wifi.EAPConstants; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSP; import android.os.Parcel; @@ -44,7 +46,9 @@ public class PasspointConfigurationTest { cred.realm = "realm"; cred.userCredential = null; cred.certCredential = null; - cred.simCredential = null; + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "1234*"; + cred.simCredential.eapType = EAPConstants.EAP_SIM; cred.caCertificate = null; cred.clientCertificateChain = null; cred.clientPrivateKey = null; @@ -61,11 +65,20 @@ public class PasspointConfigurationTest { assertTrue(readConfig.equals(writeConfig)); } + /** + * Verify parcel read/write for a default configuration. + * + * @throws Exception + */ @Test public void verifyParcelWithDefault() throws Exception { verifyParcel(new PasspointConfiguration()); } + /** + * Verify parcel read/write for a configuration that contained both HomeSP and Credential. + * @throws Exception + */ @Test public void verifyParcelWithHomeSPAndCredential() throws Exception { PasspointConfiguration config = new PasspointConfiguration(); @@ -74,6 +87,11 @@ public class PasspointConfigurationTest { verifyParcel(config); } + /** + * Verify parcel read/write for a configuration that contained only HomeSP. + * + * @throws Exception + */ @Test public void verifyParcelWithHomeSPOnly() throws Exception { PasspointConfiguration config = new PasspointConfiguration(); @@ -81,10 +99,63 @@ public class PasspointConfigurationTest { verifyParcel(config); } + /** + * Verify parcel read/write for a configuration that contained only Credential. + * + * @throws Exception + */ @Test public void verifyParcelWithCredentialOnly() throws Exception { PasspointConfiguration config = new PasspointConfiguration(); config.credential = createCredential(); verifyParcel(config); } + + /** + * Verify that a default/empty configuration is invalid. + * + * @throws Exception + */ + @Test + public void validateDefaultConfig() throws Exception { + PasspointConfiguration config = new PasspointConfiguration(); + assertFalse(config.validate()); + } + + /** + * Verify that a configuration without Credential is invalid. + * + * @throws Exception + */ + @Test + public void validateConfigWithoutCredential() throws Exception { + PasspointConfiguration config = new PasspointConfiguration(); + config.homeSp = createHomeSp(); + assertFalse(config.validate()); + } + + /** + * Verify that a a configuration without HomeSP is invalid. + * + * @throws Exception + */ + @Test + public void validateConfigWithoutHomeSp() throws Exception { + PasspointConfiguration config = new PasspointConfiguration(); + config.credential = createCredential(); + assertFalse(config.validate()); + } + + /** + * Verify a valid configuration. + * + * @throws Exception + */ + @Test + public void validateValidConfig() throws Exception { + PasspointConfiguration config = new PasspointConfiguration(); + config.homeSp = createHomeSp(); + config.credential = createCredential(); + assertTrue(config.validate()); + } }
\ No newline at end of file diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java index 68ac4efa214f..223aa5231b36 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java @@ -16,14 +16,19 @@ package android.net.wifi.hotspot2.pps; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.net.wifi.EAPConstants; import android.net.wifi.FakeKeys; import android.os.Parcel; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import java.security.MessageDigest; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.util.Arrays; import org.junit.Test; @@ -52,15 +57,15 @@ public class CredentialTest { private static Credential createCredentialWithCertificateCredential() { Credential.CertificateCredential certCred = new Credential.CertificateCredential(); certCred.certType = "x509v3"; - certCred.certSha256FingerPrint = new byte[256]; + certCred.certSha256FingerPrint = new byte[32]; return createCredential(null, certCred, null, FakeKeys.CA_CERT0, new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1); } private static Credential createCredentialWithSimCredential() { Credential.SimCredential simCred = new Credential.SimCredential(); - simCred.imsi = "imsi"; - simCred.eapType = 1; + simCred.imsi = "1234*"; + simCred.eapType = EAPConstants.EAP_SIM; return createCredential(null, null, simCred, null, null, null); } @@ -68,7 +73,7 @@ public class CredentialTest { Credential.UserCredential userCred = new Credential.UserCredential(); userCred.username = "username"; userCred.password = "password"; - userCred.eapType = 1; + userCred.eapType = EAPConstants.EAP_TTLS; userCred.nonEapInnerMethod = "MS-CHAP"; return createCredential(userCred, null, null, FakeKeys.CA_CERT0, new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1); @@ -83,23 +88,386 @@ public class CredentialTest { assertTrue(readCred.equals(writeCred)); } + /** + * Verify parcel read/write for a default/empty credential. + * + * @throws Exception + */ @Test public void verifyParcelWithDefault() throws Exception { verifyParcel(new Credential()); } + /** + * Verify parcel read/write for a certificate credential. + * + * @throws Exception + */ @Test public void verifyParcelWithCertificateCredential() throws Exception { verifyParcel(createCredentialWithCertificateCredential()); } + /** + * Verify parcel read/write for a SIM credential. + * + * @throws Exception + */ @Test public void verifyParcelWithSimCredential() throws Exception { verifyParcel(createCredentialWithSimCredential()); } + /** + * Verify parcel read/write for an user credential. + * + * @throws Exception + */ @Test public void verifyParcelWithUserCredential() throws Exception { verifyParcel(createCredentialWithUserCredential()); } -} + + /** + * Verify a valid user credential. + * @throws Exception + */ + @Test + public void validateUserCredential() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + cred.caCertificate = FakeKeys.CA_CERT0; + assertTrue(cred.validate()); + } + + /** + * Verify that an user credential without CA Certificate is invalid. + * + * @throws Exception + */ + @Test + public void validateUserCredentialWithoutCaCert() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + assertFalse(cred.validate()); + } + + /** + * Verify that an user credential with EAP type other than EAP-TTLS is invalid. + * + * @throws Exception + */ + @Test + public void validateUserCredentialWithEapTls() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + cred.caCertificate = FakeKeys.CA_CERT0; + assertFalse(cred.validate()); + } + + + /** + * Verify that an user credential without realm is invalid. + * + * @throws Exception + */ + @Test + public void validateUserCredentialWithoutRealm() throws Exception { + Credential cred = new Credential(); + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + cred.caCertificate = FakeKeys.CA_CERT0; + assertFalse(cred.validate()); + } + + /** + * Verify that an user credential without username is invalid. + * + * @throws Exception + */ + @Test + public void validateUserCredentialWithoutUsername() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + cred.caCertificate = FakeKeys.CA_CERT0; + assertFalse(cred.validate()); + } + + /** + * Verify that an user credential without password is invalid. + * + * @throws Exception + */ + @Test + public void validateUserCredentialWithoutPassword() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + cred.caCertificate = FakeKeys.CA_CERT0; + assertFalse(cred.validate()); + } + + /** + * Verify that an user credential without auth methoh (non-EAP inner method) is invalid. + * + * @throws Exception + */ + @Test + public void validateUserCredentialWithoutAuthMethod() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.caCertificate = FakeKeys.CA_CERT0; + assertFalse(cred.validate()); + } + + /** + * Verify a certificate credential. CA Certificate, client certificate chain, + * and client private key are all required. Also the digest for client + * certificate must match the fingerprint specified in the certificate credential. + * + * @throws Exception + */ + @Test + public void validateCertCredential() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup certificate credential. + cred.certCredential = new Credential.CertificateCredential(); + cred.certCredential.certType = "x509v3"; + cred.certCredential.certSha256FingerPrint = + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()); + // Setup certificates and private key. + cred.caCertificate = FakeKeys.CA_CERT0; + cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT}; + cred.clientPrivateKey = FakeKeys.RSA_KEY1; + assertTrue(cred.validate()); + } + + /** + * Verify that an certificate credential without CA Certificate is invalid. + * + * @throws Exception + */ + public void validateCertCredentialWithoutCaCert() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup certificate credential. + cred.certCredential = new Credential.CertificateCredential(); + cred.certCredential.certType = "x509v3"; + cred.certCredential.certSha256FingerPrint = + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()); + // Setup certificates and private key. + cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT}; + cred.clientPrivateKey = FakeKeys.RSA_KEY1; + assertFalse(cred.validate()); + } + + /** + * Verify that a certificate credential without client certificate chain is invalid. + * + * @throws Exception + */ + @Test + public void validateCertCredentialWithoutClientCertChain() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup certificate credential. + cred.certCredential = new Credential.CertificateCredential(); + cred.certCredential.certType = "x509v3"; + cred.certCredential.certSha256FingerPrint = + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()); + // Setup certificates and private key. + cred.caCertificate = FakeKeys.CA_CERT0; + cred.clientPrivateKey = FakeKeys.RSA_KEY1; + assertFalse(cred.validate()); + } + + /** + * Verify that a certificate credential without client private key is invalid. + * + * @throws Exception + */ + @Test + public void validateCertCredentialWithoutClientPrivateKey() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup certificate credential. + cred.certCredential = new Credential.CertificateCredential(); + cred.certCredential.certType = "x509v3"; + cred.certCredential.certSha256FingerPrint = + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()); + // Setup certificates and private key. + cred.caCertificate = FakeKeys.CA_CERT0; + cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT}; + assertFalse(cred.validate()); + } + + /** + * Verify that a certificate credential with mismatch client certificate fingerprint + * is invalid. + * + * @throws Exception + */ + @Test + public void validateCertCredentialWithMismatchFingerprint() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup certificate credential. + cred.certCredential = new Credential.CertificateCredential(); + cred.certCredential.certType = "x509v3"; + cred.certCredential.certSha256FingerPrint = new byte[32]; + Arrays.fill(cred.certCredential.certSha256FingerPrint, (byte)0); + // Setup certificates and private key. + cred.caCertificate = FakeKeys.CA_CERT0; + cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT}; + cred.clientPrivateKey = FakeKeys.RSA_KEY1; + assertFalse(cred.validate()); + } + + /** + * Verify a SIM credential using EAP-SIM. + * + * @throws Exception + */ + @Test + public void validateSimCredentialWithEapSim() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "1234*"; + cred.simCredential.eapType = EAPConstants.EAP_SIM; + assertTrue(cred.validate()); + } + + /** + * Verify a SIM credential using EAP-AKA. + * + * @throws Exception + */ + @Test + public void validateSimCredentialWithEapAka() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "1234*"; + cred.simCredential.eapType = EAPConstants.EAP_AKA; + assertTrue(cred.validate()); + } + + /** + * Verify a SIM credential using EAP-AKA-PRIME. + * + * @throws Exception + */ + @Test + public void validateSimCredentialWithEapAkaPrime() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "1234*"; + cred.simCredential.eapType = EAPConstants.EAP_AKA_PRIME; + assertTrue(cred.validate()); + } + + /** + * Verify that a SIM credential without IMSI is invalid. + * + * @throws Exception + */ + @Test + public void validateSimCredentialWithoutIMSI() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.eapType = EAPConstants.EAP_SIM; + assertFalse(cred.validate()); + } + + /** + * Verify that a SIM credential with an invalid IMSI is invalid. + * + * @throws Exception + */ + @Test + public void validateSimCredentialWithInvalidIMSI() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "dummy"; + cred.simCredential.eapType = EAPConstants.EAP_SIM; + assertFalse(cred.validate()); + } + + /** + * Verify that a SIM credential with invalid EAP type is invalid. + * + * @throws Exception + */ + @Test + public void validateSimCredentialWithEapTls() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "1234*"; + cred.simCredential.eapType = EAPConstants.EAP_TLS; + assertFalse(cred.validate()); + } + + /** + * Verify that a credential contained both an user and a SIM credential is invalid. + * + * @throws Exception + */ + @Test + public void validateCredentialWithUserAndSimCredential() throws Exception { + Credential cred = new Credential(); + cred.realm = "realm"; + // Setup user credential with EAP-TTLS. + cred.userCredential = new Credential.UserCredential(); + cred.userCredential.username = "username"; + cred.userCredential.password = "password"; + cred.userCredential.eapType = EAPConstants.EAP_TTLS; + cred.userCredential.nonEapInnerMethod = "MS-CHAP"; + cred.caCertificate = FakeKeys.CA_CERT0; + // Setup SIM credential. + cred.simCredential = new Credential.SimCredential(); + cred.simCredential.imsi = "1234*"; + cred.simCredential.eapType = EAPConstants.EAP_SIM; + assertFalse(cred.validate()); + } +}
\ No newline at end of file diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java index 0d2da6404e7f..fff1477e833b 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java @@ -16,13 +16,12 @@ package android.net.wifi.hotspot2.pps; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.os.Parcel; import android.test.suitebuilder.annotation.SmallTest; -import java.util.HashMap; - import org.junit.Test; /** @@ -47,13 +46,76 @@ public class HomeSPTest { assertTrue(readHomeSp.equals(writeHomeSp)); } + /** + * Verify parcel read/write for an empty HomeSP. + * + * @throws Exception + */ @Test public void verifyParcelWithEmptyHomeSP() throws Exception { verifyParcel(new HomeSP()); } + /** + * Verify parcel read/write for a valid HomeSP. + * + * @throws Exception + */ @Test public void verifyParcelWithValidHomeSP() throws Exception { verifyParcel(createHomeSp()); } + + /** + * Verify that a HomeSP is valid when both FQDN and Friendly Name + * are provided. + * + * @throws Exception + */ + @Test + public void validateValidHomeSP() throws Exception { + HomeSP homeSp = new HomeSP(); + homeSp.fqdn = "fqdn"; + homeSp.friendlyName = "friendly name"; + assertTrue(homeSp.validate()); + } + + /** + * Verify that a HomeSP is not valid when FQDN is not provided + * + * @throws Exception + */ + @Test + public void validateHomeSpWithoutFqdn() throws Exception { + HomeSP homeSp = new HomeSP(); + homeSp.friendlyName = "friendly name"; + assertFalse(homeSp.validate()); + } + + /** + * Verify that a HomeSP is not valid when Friendly Name is not provided + * + * @throws Exception + */ + @Test + public void validateHomeSpWithoutFriendlyName() throws Exception { + HomeSP homeSp = new HomeSP(); + homeSp.fqdn = "fqdn"; + assertFalse(homeSp.validate()); + } + + /** + * Verify that a HomeSP is valid when the optional Roaming Consortium OIs are + * provided. + * + * @throws Exception + */ + @Test + public void validateHomeSpWithRoamingConsoritums() throws Exception { + HomeSP homeSp = new HomeSP(); + homeSp.fqdn = "fqdn"; + homeSp.friendlyName = "friendly name"; + homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66}; + assertTrue(homeSp.validate()); + } } |