diff options
1062 files changed, 25759 insertions, 9091 deletions
diff --git a/Android.mk b/Android.mk index 6f9680347655..552103d4d1a5 100644 --- a/Android.mk +++ b/Android.mk @@ -245,12 +245,15 @@ LOCAL_SRC_FILES += \ core/java/android/os/IUpdateLock.aidl \ core/java/android/os/IUserManager.aidl \ core/java/android/os/IVibratorService.aidl \ - core/java/android/os/storage/IMountService.aidl \ - core/java/android/os/storage/IMountServiceListener.aidl \ - core/java/android/os/storage/IMountShutdownObserver.aidl \ + core/java/android/os/storage/IStorageManager.aidl \ + core/java/android/os/storage/IStorageEventListener.aidl \ + core/java/android/os/storage/IStorageShutdownObserver.aidl \ core/java/android/os/storage/IObbActionListener.aidl \ core/java/android/security/IKeystoreService.aidl \ core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \ + core/java/android/service/autofill/IAutoFillCallback.aidl \ + core/java/android/service/autofill/IAutoFillManagerService.aidl \ + core/java/android/service/autofill/IAutoFillService.aidl \ core/java/android/service/carrier/ICarrierService.aidl \ core/java/android/service/carrier/ICarrierMessagingCallback.aidl \ core/java/android/service/carrier/ICarrierMessagingService.aidl \ @@ -485,7 +488,7 @@ LOCAL_SRC_FILES += \ ../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \ ../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \ -LOCAL_SRC_FILES += \ +LOCAL_SRC_FILES += \ ../../system/netd/server/binder/android/net/INetd.aidl \ LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings @@ -517,6 +520,7 @@ LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp core-junit bouncyca LOCAL_STATIC_JAVA_LIBRARIES := \ framework-protos \ android.hardware.thermal@1.0-java-constants \ + android.hardware.health@1.0-java-constants \ LOCAL_MODULE := framework diff --git a/CleanSpec.mk b/CleanSpec.mk index cee8fdb9a856..71e6af7e90fb 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -241,6 +241,7 @@ $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framewo $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit1_intermediates/src/com/android/test/split/feature/R.java) $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit2_intermediates/src/com/android/test/split/feature/R.java) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/os/storage/*) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER 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/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java index 88cb8e6c75aa..f56c76332faa 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java @@ -16,7 +16,6 @@ package android.multiuser; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IStopUserCallback; import android.app.UserSwitchObserver; @@ -86,7 +85,7 @@ public class UserLifecycleTest { final Context context = InstrumentationRegistry.getContext(); mUm = UserManager.get(context); mAm = context.getSystemService(ActivityManager.class); - mIam = ActivityManagerNative.getDefault(); + mIam = ActivityManager.getService(); mState = mPerfStatusReporter.getBenchmarkState(); mUsersToRemove = new ArrayList<>(); } @@ -249,7 +248,7 @@ public class UserLifecycleTest { private void registerUserSwitchObserver(final CountDownLatch switchLatch, final CountDownLatch bootCompleteLatch, final int userId) throws Exception { - ActivityManagerNative.getDefault().registerUserSwitchObserver( + ActivityManager.getService().registerUserSwitchObserver( new UserSwitchObserver() { @Override public void onUserSwitchComplete(int newUserId) throws RemoteException { 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 22871fab9c06..9d93eebe1d54 100644 --- a/api/current.txt +++ b/api/current.txt @@ -18,6 +18,7 @@ package android { field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; + field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL"; field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE"; field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES"; field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE"; @@ -28,6 +29,7 @@ package android { field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD"; field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE"; field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE"; + field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"; field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"; field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE"; field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE"; @@ -577,8 +579,11 @@ package android { field public static final int focusable = 16842970; // 0x10100da field public static final int focusableInTouchMode = 16842971; // 0x10100db field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343 + field public static final int font = 16844082; // 0x1010532 field public static final int fontFamily = 16843692; // 0x10103ac field public static final int fontFeatureSettings = 16843959; // 0x10104b7 + field public static final int fontStyle = 16844081; // 0x1010531 + field public static final int fontWeight = 16844083; // 0x1010533 field public static final int footerDividersEnabled = 16843311; // 0x101022f field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521 field public static final int foreground = 16843017; // 0x1010109 @@ -3458,6 +3463,7 @@ package android.app { method public boolean dispatchTrackballEvent(android.view.MotionEvent); method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public void enterPictureInPictureMode(); + method public void enterPictureInPictureMode(float); method public android.view.View findViewById(int); method public void finish(); method public void finishActivity(int); @@ -3629,6 +3635,7 @@ package android.app { method public void setIntent(android.content.Intent); method public final void setMediaController(android.media.session.MediaController); method public void setOverlayWithDecorCaptionEnabled(boolean); + method public void setPictureInPictureAspectRatio(float); method public final deprecated void setProgress(int); method public final deprecated void setProgressBarIndeterminate(boolean); method public final deprecated void setProgressBarIndeterminateVisibility(boolean); @@ -3885,6 +3892,7 @@ package android.app { public class ActivityOptions { method public android.graphics.Rect getLaunchBounds(); + method public int getLaunchDisplayId(); method public static android.app.ActivityOptions makeBasic(); method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int); method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int); @@ -3895,6 +3903,7 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); + method public android.app.ActivityOptions setLaunchDisplayId(int); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; @@ -4649,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); @@ -4947,9 +4956,9 @@ package android.app { ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public int describeContents(); + method public java.lang.String getChannel(); method public java.lang.String getGroup(); method public android.graphics.drawable.Icon getLargeIcon(); - method public java.lang.String getNotificationChannel(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); method public void writeToParcel(android.os.Parcel, int); @@ -5343,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(); @@ -5976,6 +5985,7 @@ package android.app.admin { method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName); method public void addUserRestriction(android.content.ComponentName, java.lang.String); + method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle); method public void clearCrossProfileIntentFilters(android.content.ComponentName); method public void clearDeviceOwnerApp(java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); @@ -6258,6 +6268,7 @@ package android.app.assist { public static class AssistStructure.ViewNode { method public float getAlpha(); + method public int getAutoFillId(); method public android.app.assist.AssistStructure.ViewNode getChildAt(int); method public int getChildCount(); method public java.lang.String getClassName(); @@ -7897,6 +7908,7 @@ package android.content { method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); + method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); method protected final void setPathPermissions(android.content.pm.PathPermission[]); method protected final void setReadPermission(java.lang.String); method protected final void setWritePermission(java.lang.String); @@ -8030,6 +8042,7 @@ package android.content { method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); + method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver); method public void releasePersistableUriPermission(android.net.Uri, int); method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle); @@ -19901,6 +19914,7 @@ package android.media { field public static final int SCO_AUDIO_STATE_CONNECTING = 2; // 0x2 field public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; // 0x0 field public static final int SCO_AUDIO_STATE_ERROR = -1; // 0xffffffff + field public static final int STREAM_ACCESSIBILITY = 10; // 0xa field public static final int STREAM_ALARM = 4; // 0x4 field public static final int STREAM_DTMF = 8; // 0x8 field public static final int STREAM_MUSIC = 3; // 0x3 @@ -29330,6 +29344,7 @@ package android.os { method public void finishBroadcast(); method public java.lang.Object getBroadcastCookie(int); method public E getBroadcastItem(int); + method public java.lang.Object getRegisteredCallbackCookie(int); method public int getRegisteredCallbackCount(); method public void kill(); method public void onCallbackDied(E); @@ -32074,6 +32089,7 @@ package android.provider { field public static final java.lang.String EXTRA_ERROR = "error"; field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; field public static final java.lang.String EXTRA_INFO = "info"; + field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI"; field public static final java.lang.String EXTRA_LOADING = "loading"; field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION"; field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT"; @@ -32181,6 +32197,7 @@ package android.provider { public final class MediaStore { ctor public MediaStore(); + method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri getMediaScannerUri(); method public static java.lang.String getVersion(android.content.Context); field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; @@ -34627,6 +34644,33 @@ package android.security.keystore { } +package android.service.autofill { + + public abstract class AutoFillService extends android.app.Service { + ctor public AutoFillService(); + method public final android.os.IBinder onBind(android.content.Intent); + method public void onConnected(); + method public void onDisconnected(); + method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; + } + + public final class FillCallback { + method public void onFailure(java.lang.CharSequence); + method public void onSuccess(android.service.autofill.FillCallback.FillData); + } + + public static final class FillCallback.FillData { + } + + public static class FillCallback.FillData.Builder { + ctor public FillCallback.FillData.Builder(); + method public android.service.autofill.FillCallback.FillData build(); + method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String); + } + +} + package android.service.carrier { public class CarrierIdentifier implements android.os.Parcelable { @@ -34829,6 +34873,21 @@ package android.service.media { package android.service.notification { + public final class Adjustment implements android.os.Parcelable { + ctor public Adjustment(java.lang.String, java.lang.String, int, android.os.Bundle, java.lang.CharSequence, android.net.Uri, int); + ctor protected Adjustment(android.os.Parcel); + method public int describeContents(); + method public java.lang.CharSequence getExplanation(); + method public int getImportance(); + method public java.lang.String getKey(); + method public java.lang.String getPackage(); + method public android.net.Uri getReference(); + method public android.os.Bundle getSignals(); + method public int getUser(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR; + } + public final class Condition implements android.os.Parcelable { ctor public Condition(android.net.Uri, java.lang.String, int); ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int); @@ -34875,6 +34934,15 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService"; } + public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { + ctor public NotificationAssistantService(); + method public final void adjustNotification(android.service.notification.Adjustment); + method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; + } + public abstract class NotificationListenerService extends android.app.Service { ctor public NotificationListenerService(); method public final void cancelAllNotifications(); @@ -34896,6 +34964,7 @@ package android.service.notification { method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRemoved(android.service.notification.StatusBarNotification); method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); + method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); method public static void requestRebind(android.content.ComponentName); @@ -34910,6 +34979,25 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 + field public static final int REASON_APP_CANCEL = 8; // 0x8 + field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 + field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 + field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 + field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 + field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 + field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 + field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd + field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc + field public static final int REASON_LISTENER_CANCEL = 10; // 0xa + field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb + field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 + field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 + field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe + field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf + field public static final int REASON_SNOOZED = 18; // 0x12 + field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10 + field public static final int REASON_USER_STOPPED = 6; // 0x6 + field public static final int REASON_USER_SWITCH = 19; // 0x13 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1 field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2 @@ -34936,7 +35024,7 @@ package android.service.notification { } public class StatusBarNotification implements android.os.Parcelable { - ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long); + ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long); ctor public StatusBarNotification(android.os.Parcel); method public android.service.notification.StatusBarNotification clone(); method public int describeContents(); @@ -34944,6 +35032,7 @@ package android.service.notification { method public int getId(); method public java.lang.String getKey(); method public android.app.Notification getNotification(); + method public android.app.NotificationChannel getNotificationChannel(); method public java.lang.String getOverrideGroupKey(); method public java.lang.String getPackageName(); method public long getPostTime(); @@ -36511,6 +36600,7 @@ package android.telecom { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); method public void setCallDataUsage(long); field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5 + field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7 field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6 field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 @@ -36661,6 +36751,7 @@ package android.telecom { field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 + field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8 field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100 field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR; @@ -37182,8 +37273,12 @@ package android.telephony { method public int describeContents(); method public boolean equals(java.lang.Object); method public int getAsuLevel(); + method public int getCqi(); method public int getDbm(); method public int getLevel(); + method public int getRsrp(); + method public int getRsrq(); + method public int getRssnr(); method public int getTimingAdvance(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); @@ -37529,6 +37624,7 @@ package android.telephony { public class TelephonyManager { method public boolean canChangeDtmfToneLength(); + method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); method public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); @@ -37551,6 +37647,7 @@ package android.telephony { method public int getNetworkType(); method public int getPhoneCount(); method public int getPhoneType(); + method public android.telephony.ServiceState getServiceState(); method public java.lang.String getSimCountryIso(); method public java.lang.String getSimOperator(); method public java.lang.String getSimOperatorName(); @@ -37578,6 +37675,7 @@ package android.telephony { method public void listen(android.telephony.PhoneStateListener, int); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); + method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); method public boolean setOperatorBrandOverride(java.lang.String); method public boolean setPreferredNetworkTypeToGlobal(); @@ -37585,6 +37683,7 @@ package android.telephony { field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL"; field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; + field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 field public static final int APPTYPE_RUIM = 3; // 0x3 @@ -37604,11 +37703,15 @@ package android.telephony { field public static final int DATA_CONNECTING = 1; // 0x1 field public static final int DATA_DISCONNECTED = 0; // 0x0 field public static final int DATA_SUSPENDED = 3; // 0x3 + field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT"; field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number"; + field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT"; + field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT"; field public static final java.lang.String EXTRA_STATE = "state"; field public static final java.lang.String EXTRA_STATE_IDLE; field public static final java.lang.String EXTRA_STATE_OFFHOOK; field public static final java.lang.String EXTRA_STATE_RINGING; + field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER"; field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 @@ -40504,6 +40607,45 @@ package android.util { method public abstract void setValue(T, float); } + public final class Half { + method public static short abs(short); + method public static short ceil(short); + method public static short copySign(short, short); + method public static boolean equals(short, short); + method public static short floor(short); + method public static int getExponent(short); + method public static int getSign(short); + method public static int getSignificand(short); + method public static boolean greater(short, short); + method public static boolean greaterEquals(short, short); + method public static boolean isInfinite(short); + method public static boolean isNaN(short); + method public static boolean isNormalized(short); + method public static boolean less(short, short); + method public static boolean lessEquals(short, short); + method public static short max(short, short); + method public static short min(short, short); + method public static short round(short); + method public static float toFloat(short); + method public static java.lang.String toHexString(short); + method public static java.lang.String toString(short); + method public static short trunc(short); + method public static short valueOf(float); + field public static final short EPSILON = 5120; // 0x1400 + field public static final short LOWEST_VALUE = -1025; // 0xfffffbff + field public static final int MAX_EXPONENT = 15; // 0xf + field public static final short MAX_VALUE = 31743; // 0x7bff + field public static final int MIN_EXPONENT = -14; // 0xfffffff2 + field public static final short MIN_NORMAL = 1024; // 0x400 + field public static final short MIN_VALUE = 1; // 0x1 + field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00 + field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000 + field public static final short NaN = 32256; // 0x7e00 + field public static final short POSITIVE_INFINITY = 31744; // 0x7c00 + field public static final short POSITIVE_ZERO = 0; // 0x0 + field public static final int SIZE = 16; // 0x10 + } + public abstract class IntProperty<T> extends android.util.Property { ctor public IntProperty(java.lang.String); method public final void set(T, java.lang.Integer); @@ -44983,6 +45125,7 @@ package android.view.inputmethod { field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000 field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000 field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000 + field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000 field public static final int IME_MASK_ACTION = 255; // 0xff field public static final int IME_NULL = 0; // 0x0 field public int actionId; @@ -58950,8 +59093,8 @@ package java.util { method public static void rotate(java.util.List<?>, int); method public static void shuffle(java.util.List<?>); method public static void shuffle(java.util.List<?>, java.util.Random); - method public static <E> java.util.Set<E> singleton(E); - method public static <E> java.util.List<E> singletonList(E); + method public static <T> java.util.Set<T> singleton(T); + method public static <T> java.util.List<T> singletonList(T); method public static <K, V> java.util.Map<K, V> singletonMap(K, V); method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>); method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>); @@ -63220,7 +63363,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(); @@ -63229,7 +63375,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); @@ -63300,6 +63449,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 a8a725eda771..e8874647ce26 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -28,6 +28,7 @@ package android { field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; + field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL"; field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE"; field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES"; field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE"; @@ -41,6 +42,7 @@ package android { field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET"; field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE"; field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE"; + field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"; field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"; field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"; field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE"; @@ -130,6 +132,7 @@ package android { field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS"; field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS"; + field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL"; field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES"; field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; @@ -683,8 +686,11 @@ package android { field public static final int focusable = 16842970; // 0x10100da field public static final int focusableInTouchMode = 16842971; // 0x10100db field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343 + field public static final int font = 16844082; // 0x1010532 field public static final int fontFamily = 16843692; // 0x10103ac field public static final int fontFeatureSettings = 16843959; // 0x10104b7 + field public static final int fontStyle = 16844081; // 0x1010531 + field public static final int fontWeight = 16844083; // 0x1010533 field public static final int footerDividersEnabled = 16843311; // 0x101022f field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521 field public static final int foreground = 16843017; // 0x1010109 @@ -3574,6 +3580,7 @@ package android.app { method public boolean dispatchTrackballEvent(android.view.MotionEvent); method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public void enterPictureInPictureMode(); + method public void enterPictureInPictureMode(float); method public android.view.View findViewById(int); method public void finish(); method public void finishActivity(int); @@ -3747,6 +3754,7 @@ package android.app { method public void setIntent(android.content.Intent); method public final void setMediaController(android.media.session.MediaController); method public void setOverlayWithDecorCaptionEnabled(boolean); + method public void setPictureInPictureAspectRatio(float); method public final deprecated void setProgress(int); method public final deprecated void setProgressBarIndeterminate(boolean); method public final deprecated void setProgressBarIndeterminateVisibility(boolean); @@ -4016,6 +4024,7 @@ package android.app { public class ActivityOptions { method public android.graphics.Rect getLaunchBounds(); + method public int getLaunchDisplayId(); method public static android.app.ActivityOptions makeBasic(); method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int); method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int); @@ -4026,6 +4035,7 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); + method public android.app.ActivityOptions setLaunchDisplayId(int); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; @@ -4544,8 +4554,11 @@ package android.app { public abstract class EphemeralResolverService extends android.app.Service { ctor public EphemeralResolverService(); method public final void attachBaseContext(android.content.Context); + method public android.os.Looper getLooper(); method public final android.os.IBinder onBind(android.content.Intent); - method public abstract java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], int); + method public abstract deprecated java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], 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"; } @@ -4799,7 +4812,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); @@ -5097,9 +5110,9 @@ package android.app { ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public int describeContents(); + method public java.lang.String getChannel(); method public java.lang.String getGroup(); method public android.graphics.drawable.Icon getLargeIcon(); - method public java.lang.String getNotificationChannel(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); method public void writeToParcel(android.os.Parcel, int); @@ -5495,7 +5508,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); @@ -5503,7 +5516,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(); @@ -5515,7 +5528,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 } @@ -6144,6 +6157,7 @@ package android.app.admin { method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName); method public void addUserRestriction(android.content.ComponentName, java.lang.String); + method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle); method public void clearCrossProfileIntentFilters(android.content.ComponentName); method public void clearDeviceOwnerApp(java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); @@ -6446,6 +6460,7 @@ package android.app.assist { public static class AssistStructure.ViewNode { method public float getAlpha(); + method public int getAutoFillId(); method public android.app.assist.AssistStructure.ViewNode getChildAt(int); method public int getChildCount(); method public java.lang.String getClassName(); @@ -8226,6 +8241,7 @@ package android.content { method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); + method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); method protected final void setPathPermissions(android.content.pm.PathPermission[]); method protected final void setReadPermission(java.lang.String); method protected final void setWritePermission(java.lang.String); @@ -8359,6 +8375,7 @@ package android.content { method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); + method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver); method public void releasePersistableUriPermission(android.net.Uri, int); method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle); @@ -9189,6 +9206,7 @@ package android.content { field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT"; field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME"; field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; + field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME"; field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM"; field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT"; field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE"; @@ -9893,18 +9911,39 @@ package android.content.pm { field public int reqTouchScreen; } + public final class EphemeralIntentFilter implements android.os.Parcelable { + ctor public EphemeralIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>); + method public int describeContents(); + method public java.util.List<android.content.IntentFilter> getFilters(); + method public java.lang.String getSplitName(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralIntentFilter> CREATOR; + } + public final class EphemeralResolveInfo implements android.os.Parcelable { - ctor public EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>); + ctor public deprecated EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>); + ctor public EphemeralResolveInfo(android.content.pm.EphemeralResolveInfo.EphemeralDigest, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>); + ctor public EphemeralResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>); method public int describeContents(); method public byte[] getDigestBytes(); method public int getDigestPrefix(); - method public java.util.List<android.content.IntentFilter> getFilters(); + method public deprecated java.util.List<android.content.IntentFilter> getFilters(); + method public java.util.List<android.content.pm.EphemeralIntentFilter> getIntentFilters(); method public java.lang.String getPackageName(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo> CREATOR; field public static final java.lang.String SHA_ALGORITHM = "SHA-256"; } + public static final class EphemeralResolveInfo.EphemeralDigest implements android.os.Parcelable { + ctor public EphemeralResolveInfo.EphemeralDigest(java.lang.String); + method public int describeContents(); + method public byte[][] getDigestBytes(); + method public int[] getDigestPrefix(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo.EphemeralDigest> CREATOR; + } + public final class FeatureGroupInfo implements android.os.Parcelable { ctor public FeatureGroupInfo(); ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo); @@ -21437,6 +21476,7 @@ package android.media { field public static final int SCO_AUDIO_STATE_CONNECTING = 2; // 0x2 field public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; // 0x0 field public static final int SCO_AUDIO_STATE_ERROR = -1; // 0xffffffff + field public static final int STREAM_ACCESSIBILITY = 10; // 0xa field public static final int STREAM_ALARM = 4; // 0x4 field public static final int STREAM_DTMF = 8; // 0x8 field public static final int STREAM_MUSIC = 3; // 0x3 @@ -31858,6 +31898,7 @@ package android.os { method public void finishBroadcast(); method public java.lang.Object getBroadcastCookie(int); method public E getBroadcastItem(int); + method public java.lang.Object getRegisteredCallbackCookie(int); method public int getRegisteredCallbackCount(); method public void kill(); method public void onCallbackDied(E); @@ -34737,6 +34778,7 @@ package android.provider { field public static final java.lang.String EXTRA_ERROR = "error"; field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; field public static final java.lang.String EXTRA_INFO = "info"; + field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI"; field public static final java.lang.String EXTRA_LOADING = "loading"; field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION"; field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT"; @@ -34844,6 +34886,7 @@ package android.provider { public final class MediaStore { ctor public MediaStore(); + method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri getMediaScannerUri(); method public static java.lang.String getVersion(android.content.Context); field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; @@ -35338,6 +35381,7 @@ package android.provider { field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS"; field public static final java.lang.String ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS"; field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS"; + field public static final java.lang.String ACTION_WIFI_SAVED_NETWORK_SETTINGS = "android.settings.WIFI_SAVED_NETWORK_SETTINGS"; field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"; field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"; field public static final java.lang.String AUTHORITY = "settings"; @@ -37395,6 +37439,33 @@ package android.security.keystore { } +package android.service.autofill { + + public abstract class AutoFillService extends android.app.Service { + ctor public AutoFillService(); + method public final android.os.IBinder onBind(android.content.Intent); + method public void onConnected(); + method public void onDisconnected(); + method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; + } + + public final class FillCallback { + method public void onFailure(java.lang.CharSequence); + method public void onSuccess(android.service.autofill.FillCallback.FillData); + } + + public static final class FillCallback.FillData { + } + + public static class FillCallback.FillData.Builder { + ctor public FillCallback.FillData.Builder(); + method public android.service.autofill.FillCallback.FillData build(); + method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String); + } + +} + package android.service.carrier { public class CarrierIdentifier implements android.os.Parcelable { @@ -37658,6 +37729,15 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService"; } + public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { + ctor public NotificationAssistantService(); + method public final void adjustNotification(android.service.notification.Adjustment); + method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; + } + public abstract class NotificationListenerService extends android.app.Service { ctor public NotificationListenerService(); method public final void cancelAllNotifications(); @@ -37681,6 +37761,7 @@ package android.service.notification { method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRemoved(android.service.notification.StatusBarNotification); method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); + method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int); method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException; method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); @@ -37698,6 +37779,25 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 + field public static final int REASON_APP_CANCEL = 8; // 0x8 + field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 + field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 + field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 + field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 + field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 + field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 + field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd + field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc + field public static final int REASON_LISTENER_CANCEL = 10; // 0xa + field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb + field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 + field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 + field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe + field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf + field public static final int REASON_SNOOZED = 18; // 0x12 + field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10 + field public static final int REASON_USER_STOPPED = 6; // 0x6 + field public static final int REASON_USER_SWITCH = 19; // 0x13 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1 field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2 @@ -37725,39 +37825,8 @@ package android.service.notification { field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR; } - public abstract class NotificationRankerService extends android.service.notification.NotificationListenerService { - ctor public NotificationRankerService(); - method public final void adjustNotification(android.service.notification.Adjustment); - method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); - method public final android.os.IBinder onBind(android.content.Intent); - method public void onNotificationActionClick(java.lang.String, long, int); - method public void onNotificationClick(java.lang.String, long); - method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); - method public void onNotificationRemoved(java.lang.String, long, int); - method public void onNotificationVisibilityChanged(java.lang.String, long, boolean); - field public static final int REASON_APP_CANCEL = 8; // 0x8 - field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 - field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 - field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 - field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 - field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 - field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 - field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd - field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc - field public static final int REASON_LISTENER_CANCEL = 10; // 0xa - field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb - field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 - field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 - field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe - field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf - field public static final int REASON_SNOOZED = 18; // 0x12 - field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10 - field public static final int REASON_USER_STOPPED = 6; // 0x6 - field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationRankerService"; - } - public class StatusBarNotification implements android.os.Parcelable { - ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long); + ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long); ctor public StatusBarNotification(android.os.Parcel); method public android.service.notification.StatusBarNotification clone(); method public int describeContents(); @@ -37765,6 +37834,7 @@ package android.service.notification { method public int getId(); method public java.lang.String getKey(); method public android.app.Notification getNotification(); + method public android.app.NotificationChannel getNotificationChannel(); method public java.lang.String getOverrideGroupKey(); method public java.lang.String getPackageName(); method public long getPostTime(); @@ -39420,6 +39490,7 @@ package android.telecom { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); method public void setCallDataUsage(long); field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5 + field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7 field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6 field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 @@ -39694,6 +39765,7 @@ package android.telecom { field public static final int CAPABILITY_MULTI_USER = 32; // 0x20 field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 + field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8 field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100 field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR; @@ -40281,8 +40353,12 @@ package android.telephony { method public int describeContents(); method public boolean equals(java.lang.Object); method public int getAsuLevel(); + method public int getCqi(); method public int getDbm(); method public int getLevel(); + method public int getRsrp(); + method public int getRsrq(); + method public int getRssnr(); method public int getTimingAdvance(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); @@ -40652,6 +40728,7 @@ package android.telephony { method public boolean canChangeDtmfToneLength(); method public int checkCarrierPrivilegesForPackage(java.lang.String); method public int checkCarrierPrivilegesForPackageAnyPhone(java.lang.String); + method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); method public void dial(java.lang.String); method public boolean disableDataConnectivity(); @@ -40689,6 +40766,7 @@ package android.telephony { method public int getNetworkType(); method public int getPhoneCount(); method public int getPhoneType(); + method public android.telephony.ServiceState getServiceState(); method public java.lang.String getSimCountryIso(); method public java.lang.String getSimOperator(); method public java.lang.String getSimOperatorName(); @@ -40727,6 +40805,7 @@ package android.telephony { method public boolean needsOtaServiceProvisioning(); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); + method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); method public void setDataEnabled(boolean); method public void setDataEnabled(int, boolean); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); @@ -43692,6 +43771,45 @@ package android.util { method public abstract void setValue(T, float); } + public final class Half { + method public static short abs(short); + method public static short ceil(short); + method public static short copySign(short, short); + method public static boolean equals(short, short); + method public static short floor(short); + method public static int getExponent(short); + method public static int getSign(short); + method public static int getSignificand(short); + method public static boolean greater(short, short); + method public static boolean greaterEquals(short, short); + method public static boolean isInfinite(short); + method public static boolean isNaN(short); + method public static boolean isNormalized(short); + method public static boolean less(short, short); + method public static boolean lessEquals(short, short); + method public static short max(short, short); + method public static short min(short, short); + method public static short round(short); + method public static float toFloat(short); + method public static java.lang.String toHexString(short); + method public static java.lang.String toString(short); + method public static short trunc(short); + method public static short valueOf(float); + field public static final short EPSILON = 5120; // 0x1400 + field public static final short LOWEST_VALUE = -1025; // 0xfffffbff + field public static final int MAX_EXPONENT = 15; // 0xf + field public static final short MAX_VALUE = 31743; // 0x7bff + field public static final int MIN_EXPONENT = -14; // 0xfffffff2 + field public static final short MIN_NORMAL = 1024; // 0x400 + field public static final short MIN_VALUE = 1; // 0x1 + field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00 + field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000 + field public static final short NaN = 32256; // 0x7e00 + field public static final short POSITIVE_INFINITY = 31744; // 0x7c00 + field public static final short POSITIVE_ZERO = 0; // 0x0 + field public static final int SIZE = 16; // 0x10 + } + public abstract class IntProperty<T> extends android.util.Property { ctor public IntProperty(java.lang.String); method public final void set(T, java.lang.Integer); @@ -48174,6 +48292,7 @@ package android.view.inputmethod { field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000 field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000 field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000 + field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000 field public static final int IME_MASK_ACTION = 255; // 0xff field public static final int IME_NULL = 0; // 0x0 field public int actionId; @@ -62497,8 +62616,8 @@ package java.util { method public static void rotate(java.util.List<?>, int); method public static void shuffle(java.util.List<?>); method public static void shuffle(java.util.List<?>, java.util.Random); - method public static <E> java.util.Set<E> singleton(E); - method public static <E> java.util.List<E> singletonList(E); + method public static <T> java.util.Set<T> singleton(T); + method public static <T> java.util.List<T> singletonList(T); method public static <K, V> java.util.Map<K, V> singletonMap(K, V); method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>); method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>); @@ -66767,7 +66886,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(); @@ -66776,7 +66898,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); @@ -66847,6 +66972,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 50dfa2a9c77e..0a76d78ef8cc 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -18,6 +18,7 @@ package android { field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; + field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL"; field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE"; field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES"; field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE"; @@ -28,6 +29,7 @@ package android { field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD"; field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE"; field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE"; + field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"; field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"; field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE"; field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE"; @@ -577,8 +579,11 @@ package android { field public static final int focusable = 16842970; // 0x10100da field public static final int focusableInTouchMode = 16842971; // 0x10100db field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343 + field public static final int font = 16844082; // 0x1010532 field public static final int fontFamily = 16843692; // 0x10103ac field public static final int fontFeatureSettings = 16843959; // 0x10104b7 + field public static final int fontStyle = 16844081; // 0x1010531 + field public static final int fontWeight = 16844083; // 0x1010533 field public static final int footerDividersEnabled = 16843311; // 0x101022f field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521 field public static final int foreground = 16843017; // 0x1010109 @@ -3460,6 +3465,7 @@ package android.app { method public boolean dispatchTrackballEvent(android.view.MotionEvent); method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); method public void enterPictureInPictureMode(); + method public void enterPictureInPictureMode(float); method public android.view.View findViewById(int); method public void finish(); method public void finishActivity(int); @@ -3631,6 +3637,7 @@ package android.app { method public void setIntent(android.content.Intent); method public final void setMediaController(android.media.session.MediaController); method public void setOverlayWithDecorCaptionEnabled(boolean); + method public void setPictureInPictureAspectRatio(float); method public final deprecated void setProgress(int); method public final deprecated void setProgressBarIndeterminate(boolean); method public final deprecated void setProgressBarIndeterminateVisibility(boolean); @@ -3894,6 +3901,7 @@ package android.app { public class ActivityOptions { method public android.graphics.Rect getLaunchBounds(); + method public int getLaunchDisplayId(); method public static android.app.ActivityOptions makeBasic(); method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int); method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int); @@ -3904,6 +3912,7 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); + method public android.app.ActivityOptions setLaunchDisplayId(int); method public void setLaunchStackId(int); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); @@ -4659,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); @@ -4957,9 +4966,9 @@ package android.app { ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public int describeContents(); + method public java.lang.String getChannel(); method public java.lang.String getGroup(); method public android.graphics.drawable.Icon getLargeIcon(); - method public java.lang.String getNotificationChannel(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); method public void writeToParcel(android.os.Parcel, int); @@ -5353,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(); @@ -5992,6 +6001,7 @@ package android.app.admin { method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName); method public void addUserRestriction(android.content.ComponentName, java.lang.String); + method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle); method public void clearCrossProfileIntentFilters(android.content.ComponentName); method public void clearDeviceOwnerApp(java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); @@ -6274,6 +6284,7 @@ package android.app.assist { public static class AssistStructure.ViewNode { method public float getAlpha(); + method public int getAutoFillId(); method public android.app.assist.AssistStructure.ViewNode getChildAt(int); method public int getChildCount(); method public java.lang.String getClassName(); @@ -7913,6 +7924,7 @@ package android.content { method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); + method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); method protected final void setPathPermissions(android.content.pm.PathPermission[]); method protected final void setReadPermission(java.lang.String); method protected final void setWritePermission(java.lang.String); @@ -8047,6 +8059,7 @@ package android.content { method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal); + method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal); method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver); method public void releasePersistableUriPermission(android.net.Uri, int); method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle); @@ -19982,6 +19995,7 @@ package android.media { field public static final int SCO_AUDIO_STATE_CONNECTING = 2; // 0x2 field public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; // 0x0 field public static final int SCO_AUDIO_STATE_ERROR = -1; // 0xffffffff + field public static final int STREAM_ACCESSIBILITY = 10; // 0xa field public static final int STREAM_ALARM = 4; // 0x4 field public static final int STREAM_DTMF = 8; // 0x8 field public static final int STREAM_MUSIC = 3; // 0x3 @@ -29412,6 +29426,7 @@ package android.os { method public void finishBroadcast(); method public java.lang.Object getBroadcastCookie(int); method public E getBroadcastItem(int); + method public java.lang.Object getRegisteredCallbackCookie(int); method public int getRegisteredCallbackCount(); method public void kill(); method public void onCallbackDied(E); @@ -32160,6 +32175,7 @@ package android.provider { field public static final java.lang.String EXTRA_ERROR = "error"; field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; field public static final java.lang.String EXTRA_INFO = "info"; + field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI"; field public static final java.lang.String EXTRA_LOADING = "loading"; field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION"; field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT"; @@ -32267,6 +32283,7 @@ package android.provider { public final class MediaStore { ctor public MediaStore(); + method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri getMediaScannerUri(); method public static java.lang.String getVersion(android.content.Context); field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; @@ -32763,6 +32780,7 @@ package android.provider { field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins"; field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location"; field public static final java.lang.String ANDROID_ID = "android_id"; + field public static final java.lang.String AUTO_FILL_SERVICE = "auto_fill_service"; field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data"; field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on"; field public static final android.net.Uri CONTENT_URI; @@ -34716,6 +34734,33 @@ package android.security.keystore { } +package android.service.autofill { + + public abstract class AutoFillService extends android.app.Service { + ctor public AutoFillService(); + method public final android.os.IBinder onBind(android.content.Intent); + method public void onConnected(); + method public void onDisconnected(); + method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; + } + + public final class FillCallback { + method public void onFailure(java.lang.CharSequence); + method public void onSuccess(android.service.autofill.FillCallback.FillData); + } + + public static final class FillCallback.FillData { + } + + public static class FillCallback.FillData.Builder { + ctor public FillCallback.FillData.Builder(); + method public android.service.autofill.FillCallback.FillData build(); + method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String); + } + +} + package android.service.carrier { public class CarrierIdentifier implements android.os.Parcelable { @@ -34918,6 +34963,21 @@ package android.service.media { package android.service.notification { + public final class Adjustment implements android.os.Parcelable { + ctor public Adjustment(java.lang.String, java.lang.String, int, android.os.Bundle, java.lang.CharSequence, android.net.Uri, int); + ctor protected Adjustment(android.os.Parcel); + method public int describeContents(); + method public java.lang.CharSequence getExplanation(); + method public int getImportance(); + method public java.lang.String getKey(); + method public java.lang.String getPackage(); + method public android.net.Uri getReference(); + method public android.os.Bundle getSignals(); + method public int getUser(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR; + } + public final class Condition implements android.os.Parcelable { ctor public Condition(android.net.Uri, java.lang.String, int); ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int); @@ -34964,6 +35024,15 @@ package android.service.notification { field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService"; } + public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService { + ctor public NotificationAssistantService(); + method public final void adjustNotification(android.service.notification.Adjustment); + method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; + } + public abstract class NotificationListenerService extends android.app.Service { ctor public NotificationListenerService(); method public final void cancelAllNotifications(); @@ -34985,6 +35054,7 @@ package android.service.notification { method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap); method public void onNotificationRemoved(android.service.notification.StatusBarNotification); method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); + method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); method public static void requestRebind(android.content.ComponentName); @@ -34999,6 +35069,25 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3 field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 + field public static final int REASON_APP_CANCEL = 8; // 0x8 + field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 + field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 + field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 + field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 + field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 + field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 + field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd + field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc + field public static final int REASON_LISTENER_CANCEL = 10; // 0xa + field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb + field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 + field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 + field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe + field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf + field public static final int REASON_SNOOZED = 18; // 0x12 + field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10 + field public static final int REASON_USER_STOPPED = 6; // 0x6 + field public static final int REASON_USER_SWITCH = 19; // 0x13 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1 field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2 @@ -35025,7 +35114,7 @@ package android.service.notification { } public class StatusBarNotification implements android.os.Parcelable { - ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long); + ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long); ctor public StatusBarNotification(android.os.Parcel); method public android.service.notification.StatusBarNotification clone(); method public int describeContents(); @@ -35033,6 +35122,7 @@ package android.service.notification { method public int getId(); method public java.lang.String getKey(); method public android.app.Notification getNotification(); + method public android.app.NotificationChannel getNotificationChannel(); method public java.lang.String getOverrideGroupKey(); method public java.lang.String getPackageName(); method public long getPostTime(); @@ -36600,6 +36690,7 @@ package android.telecom { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); method public void setCallDataUsage(long); field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5 + field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7 field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6 field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 @@ -36750,6 +36841,7 @@ package android.telecom { field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 + field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8 field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100 field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR; @@ -37271,8 +37363,12 @@ package android.telephony { method public int describeContents(); method public boolean equals(java.lang.Object); method public int getAsuLevel(); + method public int getCqi(); method public int getDbm(); method public int getLevel(); + method public int getRsrp(); + method public int getRsrq(); + method public int getRssnr(); method public int getTimingAdvance(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); @@ -37618,6 +37714,7 @@ package android.telephony { public class TelephonyManager { method public boolean canChangeDtmfToneLength(); + method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); method public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); @@ -37640,6 +37737,7 @@ package android.telephony { method public int getNetworkType(); method public int getPhoneCount(); method public int getPhoneType(); + method public android.telephony.ServiceState getServiceState(); method public java.lang.String getSimCountryIso(); method public java.lang.String getSimOperator(); method public java.lang.String getSimOperatorName(); @@ -37667,6 +37765,7 @@ package android.telephony { method public void listen(android.telephony.PhoneStateListener, int); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); + method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); method public boolean setOperatorBrandOverride(java.lang.String); method public boolean setPreferredNetworkTypeToGlobal(); @@ -37674,6 +37773,7 @@ package android.telephony { field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL"; field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; + field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 field public static final int APPTYPE_RUIM = 3; // 0x3 @@ -37693,11 +37793,15 @@ package android.telephony { field public static final int DATA_CONNECTING = 1; // 0x1 field public static final int DATA_DISCONNECTED = 0; // 0x0 field public static final int DATA_SUSPENDED = 3; // 0x3 + field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT"; field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number"; + field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT"; + field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT"; field public static final java.lang.String EXTRA_STATE = "state"; field public static final java.lang.String EXTRA_STATE_IDLE; field public static final java.lang.String EXTRA_STATE_OFFHOOK; field public static final java.lang.String EXTRA_STATE_RINGING; + field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER"; field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 @@ -40596,6 +40700,45 @@ package android.util { method public abstract void setValue(T, float); } + public final class Half { + method public static short abs(short); + method public static short ceil(short); + method public static short copySign(short, short); + method public static boolean equals(short, short); + method public static short floor(short); + method public static int getExponent(short); + method public static int getSign(short); + method public static int getSignificand(short); + method public static boolean greater(short, short); + method public static boolean greaterEquals(short, short); + method public static boolean isInfinite(short); + method public static boolean isNaN(short); + method public static boolean isNormalized(short); + method public static boolean less(short, short); + method public static boolean lessEquals(short, short); + method public static short max(short, short); + method public static short min(short, short); + method public static short round(short); + method public static float toFloat(short); + method public static java.lang.String toHexString(short); + method public static java.lang.String toString(short); + method public static short trunc(short); + method public static short valueOf(float); + field public static final short EPSILON = 5120; // 0x1400 + field public static final short LOWEST_VALUE = -1025; // 0xfffffbff + field public static final int MAX_EXPONENT = 15; // 0xf + field public static final short MAX_VALUE = 31743; // 0x7bff + field public static final int MIN_EXPONENT = -14; // 0xfffffff2 + field public static final short MIN_NORMAL = 1024; // 0x400 + field public static final short MIN_VALUE = 1; // 0x1 + field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00 + field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000 + field public static final short NaN = 32256; // 0x7e00 + field public static final short POSITIVE_INFINITY = 31744; // 0x7c00 + field public static final short POSITIVE_ZERO = 0; // 0x0 + field public static final int SIZE = 16; // 0x10 + } + public abstract class IntProperty<T> extends android.util.Property { ctor public IntProperty(java.lang.String); method public final void set(T, java.lang.Integer); @@ -45229,6 +45372,7 @@ package android.view.inputmethod { field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000 field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000 field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000 + field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000 field public static final int IME_MASK_ACTION = 255; // 0xff field public static final int IME_NULL = 0; // 0x0 field public int actionId; @@ -59210,8 +59354,8 @@ package java.util { method public static void rotate(java.util.List<?>, int); method public static void shuffle(java.util.List<?>); method public static void shuffle(java.util.List<?>, java.util.Random); - method public static <E> java.util.Set<E> singleton(E); - method public static <E> java.util.List<E> singletonList(E); + method public static <T> java.util.Set<T> singleton(T); + method public static <T> java.util.List<T> singletonList(T); method public static <K, V> java.util.Map<K, V> singletonMap(K, V); method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>); method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>); @@ -63480,7 +63624,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(); @@ -63489,7 +63636,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); @@ -63560,6 +63710,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/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 470a0faf82fc..f003061cec3a 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -23,7 +23,6 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; -import android.app.ActivityManagerNative; import android.app.IActivityContainer; import android.app.IActivityController; import android.app.IActivityManager; @@ -108,7 +107,7 @@ public class Am extends BaseCommand { @Override public void onRun() throws Exception { - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); if (mAm == null) { System.err.println(NO_SYSTEM_ERROR_CODE); throw new AndroidException("Can't connect to activity manager; is the system running?"); diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java index 132a4f82767a..63641a8e38f4 100644 --- a/cmds/content/src/com/android/commands/content/Content.java +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -16,7 +16,7 @@ package com.android.commands.content; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ContentProviderHolder; import android.app.IActivityManager; import android.content.ContentValues; @@ -433,7 +433,7 @@ public class Content { public final void execute() { String providerName = mUri.getAuthority(); try { - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); IContentProvider provider = null; IBinder token = new Binder(); try { diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java index 31c742153f24..3ac70d668198 100644 --- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java +++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java @@ -16,7 +16,7 @@ package com.android.commands.dpm; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; @@ -117,7 +117,7 @@ public final class Dpm extends BaseCommand { mUserId = parseInt(arg); } if (mUserId == UserHandle.USER_CURRENT) { - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); try { mUserId = activityManager.getCurrentUser().id; } catch (RemoteException e) { diff --git a/cmds/locksettings/Android.mk b/cmds/locksettings/Android.mk new file mode 100644 index 000000000000..76766c7c6955 --- /dev/null +++ b/cmds/locksettings/Android.mk @@ -0,0 +1,30 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := locksettings +LOCAL_MODULE_TAGS := optional +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := locksettings +LOCAL_SRC_FILES := locksettings +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) + + diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings new file mode 100755 index 000000000000..c963b238726b --- /dev/null +++ b/cmds/locksettings/locksettings @@ -0,0 +1,5 @@ +# Script to start "locksettings" on the device +# +base=/system +export CLASSPATH=$base/framework/locksettings.jar +exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@" diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java new file mode 100644 index 000000000000..1e426d62e4e0 --- /dev/null +++ b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java @@ -0,0 +1,65 @@ +/* + * 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.commands.locksettings; + +import android.os.ResultReceiver; +import android.os.ServiceManager; +import android.os.ShellCallback; + +import com.android.internal.os.BaseCommand; +import com.android.internal.widget.ILockSettings; + +import java.io.FileDescriptor; +import java.io.PrintStream; + +public final class LockSettingsCmd extends BaseCommand { + + private static final String USAGE = + "usage: locksettings set-pattern [--old OLD_CREDENTIAL] NEW_PATTERN\n" + + " locksettings set-pin [--old OLD_CREDENTIAL] NEW_PIN\n" + + " locksettings set-password [--old OLD_CREDENTIAL] NEW_PASSWORD\n" + + " locksettings clear [--old OLD_CREDENTIAL]\n" + + "\n" + + "locksettings set-pattern: sets a pattern\n" + + " A pattern is specified by a non-separated list of numbers that index the cell\n" + + " on the pattern in a 1-based manner in left to right and top to bottom order,\n" + + " i.e. the top-left cell is indexed with 1, whereas the bottom-right cell\n" + + " is indexed with 9. Example: 1234\n" + + "\n" + + "locksettings set-pin: sets a PIN\n" + + "\n" + + "locksettings set-password: sets a password\n" + + "\n" + + "locksettings clear: clears the unlock credential\n"; + + public static void main(String[] args) { + (new LockSettingsCmd()).run(args); + } + + @Override + public void onShowUsage(PrintStream out) { + out.println(USAGE); + } + + @Override + public void onRun() throws Exception { + ILockSettings lockSettings = ILockSettings.Stub.asInterface( + ServiceManager.getService("lock_settings")); + lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, + FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {}); + } +} diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 718f1414c93d..50f46f4007d3 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -24,7 +24,6 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO import android.accounts.IAccountManager; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Context; @@ -1191,7 +1190,7 @@ public final class Pm { ClearDataObserver obs = new ClearDataObserver(); try { - ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId); + ActivityManager.getService().clearApplicationUserData(pkg, obs, userId); synchronized (obs) { while (!obs.finished) { try { diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java index d527ad73b787..4291c7768198 100644 --- a/cmds/sm/src/com/android/commands/sm/Sm.java +++ b/cmds/sm/src/com/android/commands/sm/Sm.java @@ -20,7 +20,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.storage.DiskInfo; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.util.Log; @@ -28,7 +28,7 @@ import android.util.Log; public final class Sm { private static final String TAG = "Sm"; - IMountService mSm; + IStorageManager mSm; private String[] mArgs; private int mNextArg; @@ -55,7 +55,7 @@ public final class Sm { throw new IllegalArgumentException(); } - mSm = IMountService.Stub.asInterface(ServiceManager.getService("mount")); + mSm = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); if (mSm == null) { throw new RemoteException("Failed to find running mount service"); } diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java index 86811665d9c6..32b45953fc77 100644 --- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java +++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java @@ -16,7 +16,7 @@ package com.android.uiautomator.core; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ContentProviderHolder; import android.app.IActivityManager; import android.app.UiAutomation; @@ -56,7 +56,7 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge { try { IContentProvider provider = null; Cursor cursor = null; - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); String providerName = Settings.Secure.CONTENT_URI.getAuthority(); IBinder token = new Binder(); try { diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java index ddeb8e786271..d98b4ff3e69a 100644 --- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java +++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java @@ -2,7 +2,6 @@ package com.android.uiautomator.core; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IActivityController; import android.app.IActivityManager; import android.app.UiAutomation; @@ -44,7 +43,7 @@ public class UiAutomationShellWrapper { * @see {@link ActivityManager#isUserAMonkey()} */ public void setRunAsMonkey(boolean isSet) { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (am == null) { throw new RuntimeException("Can't manage monkey status; is the system running?"); } diff --git a/compiled-classes-phone b/compiled-classes-phone index 8428e41fab4a..f09bad93132e 100644 --- a/compiled-classes-phone +++ b/compiled-classes-phone @@ -174,9 +174,6 @@ android.app.ActivityManager$TaskThumbnailInfo android.app.ActivityManager$TaskThumbnailInfo$1 android.app.ActivityManagerInternal android.app.ActivityManagerInternal$SleepToken -android.app.ActivityManagerNative -android.app.ActivityManagerNative$1 -android.app.ActivityManagerProxy android.app.ActivityOptions android.app.ActivityOptions$OnAnimationFinishedListener android.app.ActivityOptions$OnAnimationStartedListener @@ -3226,17 +3223,17 @@ android.os.health.HealthStatsParceler android.os.health.SystemHealthManager android.os.storage.DiskInfo android.os.storage.DiskInfo$1 -android.os.storage.IMountService -android.os.storage.IMountService$Stub -android.os.storage.IMountService$Stub$Proxy -android.os.storage.IMountServiceListener -android.os.storage.IMountServiceListener$Stub -android.os.storage.IMountServiceListener$Stub$Proxy -android.os.storage.IMountShutdownObserver +android.os.storage.IStorageManager +android.os.storage.IStorageManager$Stub +android.os.storage.IStorageManager$Stub$Proxy +android.os.storage.IStorageEventListener +android.os.storage.IStorageEventListener$Stub +android.os.storage.IStorageEventListener$Stub$Proxy +android.os.storage.IStorageShutdownObserver android.os.storage.IObbActionListener android.os.storage.IObbActionListener$Stub -android.os.storage.MountServiceInternal -android.os.storage.MountServiceInternal$ExternalStorageMountPolicy +android.os.storage.StorageManagerInternal +android.os.storage.StorageManagerInternal$ExternalStorageMountPolicy android.os.storage.StorageEventListener android.os.storage.StorageManager android.os.storage.StorageManager$ObbActionListener @@ -3610,9 +3607,9 @@ android.service.notification.NotificationListenerService$NotificationListenerWra android.service.notification.NotificationListenerService$Ranking android.service.notification.NotificationListenerService$RankingMap android.service.notification.NotificationListenerService$RankingMap$1 -android.service.notification.NotificationRankerService -android.service.notification.NotificationRankerService$MyHandler -android.service.notification.NotificationRankerService$NotificationRankingServiceWrapper +android.service.notification.NotificationAssistantService +android.service.notification.NotificationAssistantService$MyHandler +android.service.notification.NotificationAssistantService$NotificationRankingServiceWrapper android.service.notification.NotificationRankingUpdate android.service.notification.NotificationRankingUpdate$1 android.service.notification.StatusBarNotification diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index aed7a3693717..8c71f50d3f02 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -18,7 +18,7 @@ package android.accounts; import com.google.android.collect.Sets; import android.app.Activity; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; @@ -141,8 +141,8 @@ public class ChooseTypeAndAccountActivity extends Activity try { IBinder activityToken = getActivityToken(); - mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken); - mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( + mCallingUid = ActivityManager.getService().getLaunchedFromUid(activityToken); + mCallingPackage = ActivityManager.getService().getLaunchedFromPackage( activityToken); if (mCallingUid != 0 && mCallingPackage != null) { Bundle restrictions = UserManager.get(this) diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java new file mode 100644 index 000000000000..d3e9f08dee9e --- /dev/null +++ b/core/java/android/annotation/HalfFloat.java @@ -0,0 +1,48 @@ +/* + * 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.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * <p>Denotes that the annotated element represents a half-precision floating point + * value. Such values are stored in short data types and can be manipulated with + * the {@link android.util.Half} class. If applied to an array of short, every + * element in the array represents a half-precision float.</p> + * + * <p>Example:</p> + * + * <pre>{@code + * public abstract void setPosition(@HalfFloat short x, @HalfFloat short y, @HalfFloat short z); + * }</pre> + * + * @see android.util.Half + * @see android.util.Half#valueOf(float) + * @see android.util.Half#toFloat(short) + * + * @hide + */ +@Retention(SOURCE) +@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD}) +public @interface HalfFloat { +} diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index 0552d34d5215..58f5a787a355 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -1494,22 +1494,22 @@ public abstract class ActionBar { public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { v.setOnFocusChangeListener(null); - final View focused = mFocusRoot.findFocus(); - if (focused != null) { - focused.setOnFocusChangeListener(this); - } else { - mFocusRoot.post(this); - } + mFocusRoot.post(this); } } @Override public void run() { - if (mContainer != null) { - mContainer.setTouchscreenBlocksFocus(true); - } - if (mToolbar != null) { - mToolbar.setTouchscreenBlocksFocus(true); + final View focused = mFocusRoot.findFocus(); + if (focused != null) { + focused.setOnFocusChangeListener(this); + } else { + if (mContainer != null) { + mContainer.setTouchscreenBlocksFocus(true); + } + if (mToolbar != null) { + mToolbar.setTouchscreenBlocksFocus(true); + } } } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index b3e2f57e2b33..64e5dfc66bce 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -53,7 +53,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.Drawable; -import android.hardware.input.InputManager; import android.media.AudioManager; import android.media.session.MediaController; import android.net.Uri; @@ -70,6 +69,9 @@ import android.os.ServiceManager.ServiceNotFoundException; import android.os.StrictMode; import android.os.SystemProperties; import android.os.UserHandle; +import android.service.autofill.FillableInputField; +import android.service.autofill.AutoFillService; +import android.service.autofill.IAutoFillCallback; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -90,8 +92,6 @@ import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextThemeWrapper; import android.view.DragAndDropPermissions; import android.view.DragEvent; -import android.view.InputDevice; -import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.KeyboardShortcutGroup; import android.view.KeyboardShortcutInfo; @@ -113,9 +113,11 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView; +import android.widget.EditText; import android.widget.Toast; import android.widget.Toolbar; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; @@ -802,11 +804,13 @@ public class Activity extends ContextThemeWrapper private boolean mReleased; private boolean mUpdated; } - private final ArrayList<ManagedCursor> mManagedCursors = - new ArrayList<ManagedCursor>(); - // protected by synchronized (this) + @GuardedBy("mManagedCursors") + private final ArrayList<ManagedCursor> mManagedCursors = new ArrayList<>(); + + @GuardedBy("this") int mResultCode = RESULT_CANCELED; + @GuardedBy("this") Intent mResultData = null; private TranslucentConversionListener mTranslucentCallback; @@ -837,6 +841,9 @@ public class Activity extends ContextThemeWrapper private boolean mHasCurrentPermissionsRequest; private boolean mEatKeyUpEvent; + @GuardedBy("this") + private IAutoFillCallback mAutoFillCallback; + private static native String getDlWarning(); /** Return the intent that started this activity. */ @@ -1306,7 +1313,7 @@ public class Activity extends ContextThemeWrapper public boolean isVoiceInteractionRoot() { try { return mVoiceInteractor != null - && ActivityManagerNative.getDefault().isRootVoiceInteraction(mToken); + && ActivityManager.getService().isRootVoiceInteraction(mToken); } catch (RemoteException e) { } return false; @@ -1329,7 +1336,7 @@ public class Activity extends ContextThemeWrapper */ public boolean isLocalVoiceInteractionSupported() { try { - return ActivityManagerNative.getDefault().supportsLocalVoiceInteraction(); + return ActivityManager.getService().supportsLocalVoiceInteraction(); } catch (RemoteException re) { } return false; @@ -1343,7 +1350,7 @@ public class Activity extends ContextThemeWrapper */ public void startLocalVoiceInteraction(Bundle privateOptions) { try { - ActivityManagerNative.getDefault().startLocalVoiceInteraction(mToken, privateOptions); + ActivityManager.getService().startLocalVoiceInteraction(mToken, privateOptions); } catch (RemoteException re) { } } @@ -1372,7 +1379,7 @@ public class Activity extends ContextThemeWrapper */ public void stopLocalVoiceInteraction() { try { - ActivityManagerNative.getDefault().stopLocalVoiceInteraction(mToken); + ActivityManager.getService().stopLocalVoiceInteraction(mToken); } catch (RemoteException re) { } } @@ -1688,6 +1695,53 @@ public class Activity extends ContextThemeWrapper } /** + * Lazily gets the {@code IAutoFillCallback} for this activitity. + * + * <p>This callback is used by the {@link AutoFillService} app to auto-fill the activity fields. + */ + IAutoFillCallback getAutoFillCallback() { + synchronized (this) { + if (mAutoFillCallback == null) { + mAutoFillCallback = new IAutoFillCallback.Stub() { + @Override + public void autofill(@SuppressWarnings("rawtypes") List fields) + throws RemoteException { + runOnUiThread(() -> { + final View root = getWindow().getDecorView().getRootView(); + for (Object field : fields) { + if (!(field instanceof FillableInputField)) { + Slog.w(TAG, "autofill(): invalid type " + field.getClass()); + continue; + } + FillableInputField autoFillField = (FillableInputField) field; + final int viewId = autoFillField.getId(); + final View view = root.findViewByAccessibilityIdTraversal(viewId); + // TODO: should handle other types of view as well, but that will + // require: + // - a new interface like AutoFillable + // - a way for the views to define the type of the autofield value + if ((view instanceof EditText)) { + ((EditText) view).setText(autoFillField.getValue()); + } + } + }); + } + + @Override + public void showError(String message) { + runOnUiThread(() -> { + // TODO: temporary show a toast until it uses the Snack bar. + Toast.makeText(Activity.this, "Auto-fill request failed: " + message, + Toast.LENGTH_LONG).show(); + }); + } + }; + } + } + return mAutoFillCallback; + } + + /** * Request the Keyboard Shortcuts screen to show up. This will trigger * {@link #onProvideKeyboardShortcuts} to retrieve the shortcuts for the foreground activity. */ @@ -1744,7 +1798,7 @@ public class Activity extends ContextThemeWrapper */ public boolean showAssist(Bundle args) { try { - return ActivityManagerNative.getDefault().showAssistFromActivity(mToken, args); + return ActivityManager.getService().showAssistFromActivity(mToken, args); } catch (RemoteException e) { } return false; @@ -1860,7 +1914,7 @@ public class Activity extends ContextThemeWrapper if (mDoReportFullyDrawn) { mDoReportFullyDrawn = false; try { - ActivityManagerNative.getDefault().reportActivityFullyDrawn(mToken); + ActivityManager.getService().reportActivityFullyDrawn(mToken); } catch (RemoteException e) { } } @@ -1886,7 +1940,7 @@ public class Activity extends ContextThemeWrapper */ public boolean isInMultiWindowMode() { try { - return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken); + return ActivityManager.getService().isInMultiWindowMode(mToken); } catch (RemoteException e) { } return false; @@ -1911,7 +1965,7 @@ public class Activity extends ContextThemeWrapper */ public boolean isInPictureInPictureMode() { try { - return ActivityManagerNative.getDefault().isInPictureInPictureMode(mToken); + return ActivityManager.getService().isInPictureInPictureMode(mToken); } catch (RemoteException e) { } return false; @@ -1923,7 +1977,33 @@ public class Activity extends ContextThemeWrapper */ public void enterPictureInPictureMode() { try { - ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken); + ActivityManager.getService().enterPictureInPictureMode(mToken); + } catch (RemoteException e) { + } + } + + /** + * Puts the activity in picture-in-picture mode with a given aspect ratio. + * @see android.R.attr#supportsPictureInPicture + * + * @param aspectRatio the new aspect ratio of the picture-in-picture. + */ + public void enterPictureInPictureMode(float aspectRatio) { + try { + ActivityManagerNative.getDefault().enterPictureInPictureModeWithAspectRatio(mToken, + aspectRatio); + } catch (RemoteException e) { + } + } + + /** + * Updates the aspect ratio of the current picture-in-picture activity. + * + * @param aspectRatio the new aspect ratio of the picture-in-picture. + */ + public void setPictureInPictureAspectRatio(float aspectRatio) { + try { + ActivityManagerNative.getDefault().setPictureInPictureAspectRatio(mToken, aspectRatio); } catch (RemoteException e) { } } @@ -2957,7 +3037,7 @@ public class Activity extends ContextThemeWrapper */ @Override public void exitFreeformMode() throws RemoteException { - ActivityManagerNative.getDefault().exitFreeformMode(mToken); + ActivityManager.getService().exitFreeformMode(mToken); } /** Returns the current stack Id for the window. @@ -2965,7 +3045,7 @@ public class Activity extends ContextThemeWrapper */ @Override public int getWindowStackId() throws RemoteException { - return ActivityManagerNative.getDefault().getActivityStackId(mToken); + return ActivityManager.getService().getActivityStackId(mToken); } /** @@ -4453,7 +4533,7 @@ public class Activity extends ContextThemeWrapper fillInIntent.prepareToLeaveProcess(this); resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver()); } - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivityIntentSender(mMainThread.getApplicationThread(), intent, fillInIntent, resolvedType, mToken, who, requestCode, flagsMask, flagsValues, options); @@ -4683,7 +4763,7 @@ public class Activity extends ContextThemeWrapper } intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(this); - result = ActivityManagerNative.getDefault() + result = ActivityManager.getService() .startActivity(mMainThread.getApplicationThread(), getBasePackageName(), intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken, mEmbeddedID, requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED, @@ -4754,7 +4834,7 @@ public class Activity extends ContextThemeWrapper try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(this); - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .startNextMatchingActivity(mToken, intent, options); } catch (RemoteException e) { // Empty @@ -4952,7 +5032,7 @@ public class Activity extends ContextThemeWrapper */ public void overridePendingTransition(int enterAnim, int exitAnim) { try { - ActivityManagerNative.getDefault().overridePendingTransition( + ActivityManager.getService().overridePendingTransition( mToken, getPackageName(), enterAnim, exitAnim); } catch (RemoteException e) { } @@ -5077,7 +5157,7 @@ public class Activity extends ContextThemeWrapper @Nullable public String getCallingPackage() { try { - return ActivityManagerNative.getDefault().getCallingPackage(mToken); + return ActivityManager.getService().getCallingPackage(mToken); } catch (RemoteException e) { return null; } @@ -5100,7 +5180,7 @@ public class Activity extends ContextThemeWrapper @Nullable public ComponentName getCallingActivity() { try { - return ActivityManagerNative.getDefault().getCallingActivity(mToken); + return ActivityManager.getService().getCallingActivity(mToken); } catch (RemoteException e) { return null; } @@ -5185,7 +5265,7 @@ public class Activity extends ContextThemeWrapper throw new IllegalStateException("Must be called from main thread"); } try { - ActivityManagerNative.getDefault().requestActivityRelaunch(mToken); + ActivityManager.getService().requestActivityRelaunch(mToken); } catch (RemoteException e) { } } @@ -5207,7 +5287,7 @@ public class Activity extends ContextThemeWrapper if (resultData != null) { resultData.prepareToLeaveProcess(this); } - if (ActivityManagerNative.getDefault() + if (ActivityManager.getService() .finishActivity(mToken, resultCode, resultData, finishTask)) { mFinished = true; } @@ -5250,7 +5330,7 @@ public class Activity extends ContextThemeWrapper throw new IllegalStateException("Can not be called to deliver a result"); } try { - if (ActivityManagerNative.getDefault().finishActivityAffinity(mToken)) { + if (ActivityManager.getService().finishActivityAffinity(mToken)) { mFinished = true; } } catch (RemoteException e) { @@ -5296,7 +5376,7 @@ public class Activity extends ContextThemeWrapper public void finishActivity(int requestCode) { if (mParent == null) { try { - ActivityManagerNative.getDefault() + ActivityManager.getService() .finishSubActivity(mToken, mEmbeddedID, requestCode); } catch (RemoteException e) { // Empty @@ -5316,7 +5396,7 @@ public class Activity extends ContextThemeWrapper */ public void finishActivityFromChild(@NonNull Activity child, int requestCode) { try { - ActivityManagerNative.getDefault() + ActivityManager.getService() .finishSubActivity(mToken, child.mEmbeddedID, requestCode); } catch (RemoteException e) { // Empty @@ -5344,7 +5424,7 @@ public class Activity extends ContextThemeWrapper */ public boolean releaseInstance() { try { - return ActivityManagerNative.getDefault().releaseActivityInstance(mToken); + return ActivityManager.getService().releaseActivityInstance(mToken); } catch (RemoteException e) { // Empty } @@ -5434,7 +5514,7 @@ public class Activity extends ContextThemeWrapper try { data.prepareToLeaveProcess(this); IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, mParent == null ? mToken : mParent.mToken, mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null, @@ -5459,7 +5539,7 @@ public class Activity extends ContextThemeWrapper public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) { if (mParent == null) { try { - ActivityManagerNative.getDefault().setRequestedOrientation( + ActivityManager.getService().setRequestedOrientation( mToken, requestedOrientation); } catch (RemoteException e) { // Empty @@ -5482,7 +5562,7 @@ public class Activity extends ContextThemeWrapper public int getRequestedOrientation() { if (mParent == null) { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getRequestedOrientation(mToken); } catch (RemoteException e) { // Empty @@ -5501,7 +5581,7 @@ public class Activity extends ContextThemeWrapper */ public int getTaskId() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getTaskForActivity(mToken, false); } catch (RemoteException e) { return -1; @@ -5516,7 +5596,7 @@ public class Activity extends ContextThemeWrapper */ public boolean isTaskRoot() { try { - return ActivityManagerNative.getDefault().getTaskForActivity(mToken, true) >= 0; + return ActivityManager.getService().getTaskForActivity(mToken, true) >= 0; } catch (RemoteException e) { return false; } @@ -5535,7 +5615,7 @@ public class Activity extends ContextThemeWrapper */ public boolean moveTaskToBack(boolean nonRoot) { try { - return ActivityManagerNative.getDefault().moveActivityTaskToBack( + return ActivityManager.getService().moveActivityTaskToBack( mToken, nonRoot); } catch (RemoteException e) { // Empty @@ -5706,7 +5786,7 @@ public class Activity extends ContextThemeWrapper } } try { - ActivityManagerNative.getDefault().setTaskDescription(mToken, mTaskDescription); + ActivityManager.getService().setTaskDescription(mToken, mTaskDescription); } catch (RemoteException e) { } } @@ -5948,6 +6028,11 @@ public class Activity extends ContextThemeWrapper getWindow().peekDecorView().getViewRootImpl().dump(prefix, fd, writer, args); } + if (mAutoFillCallback != null) { + writer.print(prefix); writer.print("mAutoFillCallback: " ); + writer.println(mAutoFillCallback); + } + mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix); } @@ -5964,7 +6049,7 @@ public class Activity extends ContextThemeWrapper */ public boolean isImmersive() { try { - return ActivityManagerNative.getDefault().isImmersive(mToken); + return ActivityManager.getService().isImmersive(mToken); } catch (RemoteException e) { return false; } @@ -5982,7 +6067,7 @@ public class Activity extends ContextThemeWrapper return false; } try { - return ActivityManagerNative.getDefault().isTopOfTask(getActivityToken()); + return ActivityManager.getService().isTopOfTask(getActivityToken()); } catch (RemoteException e) { return false; } @@ -6008,7 +6093,7 @@ public class Activity extends ContextThemeWrapper public void convertFromTranslucent() { try { mTranslucentCallback = null; - if (ActivityManagerNative.getDefault().convertFromTranslucent(mToken)) { + if (ActivityManager.getService().convertFromTranslucent(mToken)) { WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, true); } } catch (RemoteException e) { @@ -6047,7 +6132,7 @@ public class Activity extends ContextThemeWrapper boolean drawComplete; try { mTranslucentCallback = callback; - mChangeCanvasToTranslucent = ActivityManagerNative.getDefault().convertToTranslucent( + mChangeCanvasToTranslucent = ActivityManager.getService().convertToTranslucent( mToken, options == null ? null : options.toBundle()); WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false); drawComplete = true; @@ -6093,7 +6178,7 @@ public class Activity extends ContextThemeWrapper ActivityOptions getActivityOptions() { try { return ActivityOptions.fromBundle( - ActivityManagerNative.getDefault().getActivityOptions(mToken)); + ActivityManager.getService().getActivityOptions(mToken)); } catch (RemoteException e) { } return null; @@ -6137,7 +6222,7 @@ public class Activity extends ContextThemeWrapper visible = false; } try { - mVisibleBehind = ActivityManagerNative.getDefault() + mVisibleBehind = ActivityManager.getService() .requestVisibleBehind(mToken, visible) && visible; } catch (RemoteException e) { mVisibleBehind = false; @@ -6178,7 +6263,7 @@ public class Activity extends ContextThemeWrapper @SystemApi public boolean isBackgroundVisibleBehind() { try { - return ActivityManagerNative.getDefault().isBackgroundVisibleBehind(mToken); + return ActivityManager.getService().isBackgroundVisibleBehind(mToken); } catch (RemoteException e) { } return false; @@ -6235,7 +6320,7 @@ public class Activity extends ContextThemeWrapper */ public void setImmersive(boolean i) { try { - ActivityManagerNative.getDefault().setImmersive(mToken, i); + ActivityManager.getService().setImmersive(mToken, i); } catch (RemoteException e) { // pass } @@ -6299,7 +6384,7 @@ public class Activity extends ContextThemeWrapper public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent) throws PackageManager.NameNotFoundException { try { - if (ActivityManagerNative.getDefault().setVrMode(mToken, enabled, requestedComponent) + if (ActivityManager.getService().setVrMode(mToken, enabled, requestedComponent) != 0) { throw new PackageManager.NameNotFoundException( requestedComponent.flattenToString()); @@ -6420,7 +6505,7 @@ public class Activity extends ContextThemeWrapper if (info.taskAffinity == null) { return false; } - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .shouldUpRecreateTask(mToken, info.taskAffinity); } catch (RemoteException e) { return false; @@ -6473,7 +6558,7 @@ public class Activity extends ContextThemeWrapper } try { upIntent.prepareToLeaveProcess(this); - return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent, + return ActivityManager.getService().navigateUpTo(mToken, upIntent, resultCode, resultData); } catch (RemoteException e) { return false; @@ -6989,7 +7074,7 @@ public class Activity extends ContextThemeWrapper */ public void startLockTask() { try { - ActivityManagerNative.getDefault().startLockTaskModeByToken(mToken); + ActivityManager.getService().startLockTaskModeByToken(mToken); } catch (RemoteException e) { } } @@ -7013,7 +7098,7 @@ public class Activity extends ContextThemeWrapper */ public void stopLockTask() { try { - ActivityManagerNative.getDefault().stopLockTaskMode(); + ActivityManager.getService().stopLockTaskMode(); } catch (RemoteException e) { } } @@ -7025,7 +7110,7 @@ public class Activity extends ContextThemeWrapper */ public void showLockTaskEscapeMessage() { try { - ActivityManagerNative.getDefault().showLockTaskEscapeMessage(mToken); + ActivityManager.getService().showLockTaskEscapeMessage(mToken); } catch (RemoteException e) { } } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9af7d8bae314..65f74d17f16c 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -36,6 +36,7 @@ import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.RoSystemProperties; import com.android.internal.os.TransferPipe; import com.android.internal.util.FastPrintWriter; +import com.android.server.LocalServices; import android.content.ComponentName; import android.content.Context; @@ -89,35 +90,22 @@ public class ActivityManager { private final Context mContext; private final Handler mHandler; + private static volatile boolean sSystemReady = false; + static final class UidObserver extends IUidObserver.Stub { final OnUidImportanceListener mListener; - final int mImportanceCutpoint; - int mLastImportance; - UidObserver(OnUidImportanceListener listener, int importanceCutpoint) { + UidObserver(OnUidImportanceListener listener) { mListener = listener; - mImportanceCutpoint = importanceCutpoint; } @Override public void onUidStateChanged(int uid, int procState) { - final boolean lastAboveCut = mLastImportance <= mImportanceCutpoint; - final int importance = RunningAppProcessInfo.procStateToImportance(procState); - final boolean newAboveCut = importance <= mImportanceCutpoint; - /* - Log.d(TAG, "Uid " + uid + " state change from " + mLastImportance + " to " - + importance + " @ cut " + mImportanceCutpoint - + ": lastAbove=" + lastAboveCut + " newAbove=" + newAboveCut); - */ - mLastImportance = importance; - if (lastAboveCut != newAboveCut) { - mListener.onUidImportance(uid, importance); - } + mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportance(procState)); } @Override - public void onUidGone(int uid) { - mLastImportance = RunningAppProcessInfo.IMPORTANCE_GONE; + public void onUidGone(int uid, boolean disabled) { mListener.onUidImportance(uid, RunningAppProcessInfo.IMPORTANCE_GONE); } @@ -126,7 +114,7 @@ public class ActivityManager { } @Override - public void onUidIdle(int uid) { + public void onUidIdle(int uid, boolean disabled) { } } @@ -380,8 +368,8 @@ public class ActivityManager { /** @hide User operation call: one of related users cannot be stopped. */ public static final int USER_OP_ERROR_RELATED_USERS_CANNOT_STOP = -4; - /** @hide Process does not exist. */ - public static final int PROCESS_STATE_NONEXISTENT = -1; + /** @hide Not a real process state. */ + public static final int PROCESS_STATE_UNKNOWN = -1; /** @hide Process is a persistent system process. */ public static final int PROCESS_STATE_PERSISTENT = 0; @@ -442,11 +430,14 @@ public class ActivityManager { /** @hide Process is being cached for later use and is empty. */ public static final int PROCESS_STATE_CACHED_EMPTY = 16; + /** @hide Process does not exist. */ + public static final int PROCESS_STATE_NONEXISTENT = 17; + /** @hide The lowest process state number */ - public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT; + public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT; /** @hide The highest process state number */ - public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY; + public static final int MAX_PROCESS_STATE = PROCESS_STATE_NONEXISTENT; /** @hide Should this process state be considered a background state? */ public static final boolean isProcStateBackground(int procState) { @@ -459,6 +450,9 @@ public class ActivityManager { /** @hide requestType for assist context: generate full AssistStructure. */ public static final int ASSIST_CONTEXT_FULL = 1; + /** @hide requestType for assist context: generate full AssistStructure for auto-fill. */ + public static final int ASSIST_CONTEXT_AUTOFILL = 2; + /** @hide Flag for registerUidObserver: report changes in process state. */ public static final int UID_OBSERVER_PROCSTATE = 1<<0; @@ -835,7 +829,7 @@ public class ActivityManager { /** @hide */ public int getFrontActivityScreenCompatMode() { try { - return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode(); + return getService().getFrontActivityScreenCompatMode(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -844,7 +838,7 @@ public class ActivityManager { /** @hide */ public void setFrontActivityScreenCompatMode(int mode) { try { - ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode); + getService().setFrontActivityScreenCompatMode(mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -853,7 +847,7 @@ public class ActivityManager { /** @hide */ public int getPackageScreenCompatMode(String packageName) { try { - return ActivityManagerNative.getDefault().getPackageScreenCompatMode(packageName); + return getService().getPackageScreenCompatMode(packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -862,7 +856,7 @@ public class ActivityManager { /** @hide */ public void setPackageScreenCompatMode(String packageName, int mode) { try { - ActivityManagerNative.getDefault().setPackageScreenCompatMode(packageName, mode); + getService().setPackageScreenCompatMode(packageName, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -871,7 +865,7 @@ public class ActivityManager { /** @hide */ public boolean getPackageAskScreenCompat(String packageName) { try { - return ActivityManagerNative.getDefault().getPackageAskScreenCompat(packageName); + return getService().getPackageAskScreenCompat(packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -880,7 +874,7 @@ public class ActivityManager { /** @hide */ public void setPackageAskScreenCompat(String packageName, boolean ask) { try { - ActivityManagerNative.getDefault().setPackageAskScreenCompat(packageName, ask); + getService().setPackageAskScreenCompat(packageName, ask); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1175,7 +1169,7 @@ public class ActivityManager { public static Bitmap loadTaskDescriptionIcon(String iconFilename, int userId) { if (iconFilename != null) { try { - return ActivityManagerNative.getDefault().getTaskDescriptionIcon(iconFilename, + return getService().getTaskDescriptionIcon(iconFilename, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1564,7 +1558,7 @@ public class ActivityManager { public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags) throws SecurityException { try { - return ActivityManagerNative.getDefault().getRecentTasks(maxNum, + return getService().getRecentTasks(maxNum, flags, UserHandle.myUserId()).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1589,7 +1583,7 @@ public class ActivityManager { public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId) throws SecurityException { try { - return ActivityManagerNative.getDefault().getRecentTasks(maxNum, + return getService().getRecentTasks(maxNum, flags, userId).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1735,7 +1729,7 @@ public class ActivityManager { ArrayList<AppTask> tasks = new ArrayList<AppTask>(); List<IBinder> appTasks; try { - appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName()); + appTasks = getService().getAppTasks(mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1760,7 +1754,7 @@ public class ActivityManager { private void ensureAppTaskThumbnailSizeLocked() { if (mAppTaskThumbnailSize == null) { try { - mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize(); + mAppTaskThumbnailSize = getService().getAppTaskThumbnailSize(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1825,7 +1819,7 @@ public class ActivityManager { description = new TaskDescription(); } try { - return ActivityManagerNative.getDefault().addAppTask(activity.getActivityToken(), + return getService().addAppTask(activity.getActivityToken(), intent, description, thumbnail); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1868,7 +1862,7 @@ public class ActivityManager { public List<RunningTaskInfo> getRunningTasks(int maxNum) throws SecurityException { try { - return ActivityManagerNative.getDefault().getTasks(maxNum, 0); + return getService().getTasks(maxNum, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1884,7 +1878,7 @@ public class ActivityManager { */ public boolean removeTask(int taskId) throws SecurityException { try { - return ActivityManagerNative.getDefault().removeTask(taskId); + return getService().removeTask(taskId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2052,7 +2046,7 @@ public class ActivityManager { /** @hide */ public TaskThumbnail getTaskThumbnail(int id) throws SecurityException { try { - return ActivityManagerNative.getDefault().getTaskThumbnail(id); + return getService().getTaskThumbnail(id); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2061,7 +2055,7 @@ public class ActivityManager { /** @hide */ public boolean isInHomeStack(int taskId) { try { - return ActivityManagerNative.getDefault().isInHomeStack(taskId); + return getService().isInHomeStack(taskId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2110,7 +2104,7 @@ public class ActivityManager { */ public void moveTaskToFront(int taskId, int flags, Bundle options) { try { - ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags, options); + getService().moveTaskToFront(taskId, flags, options); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2295,7 +2289,7 @@ public class ActivityManager { public List<RunningServiceInfo> getRunningServices(int maxNum) throws SecurityException { try { - return ActivityManagerNative.getDefault() + return getService() .getServices(maxNum, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2310,7 +2304,7 @@ public class ActivityManager { public PendingIntent getRunningServiceControlPanel(ComponentName service) throws SecurityException { try { - return ActivityManagerNative.getDefault() + return getService() .getRunningServiceControlPanel(service); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2415,7 +2409,7 @@ public class ActivityManager { */ public void getMemoryInfo(MemoryInfo outInfo) { try { - ActivityManagerNative.getDefault().getMemoryInfo(outInfo); + getService().getMemoryInfo(outInfo); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2554,7 +2548,7 @@ public class ActivityManager { */ public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) { try { - return ActivityManagerNative.getDefault().clearApplicationUserData(packageName, + return getService().clearApplicationUserData(packageName, observer, UserHandle.myUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2588,7 +2582,7 @@ public class ActivityManager { */ public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) { try { - return ActivityManagerNative.getDefault().getGrantedUriPermissions(packageName, + return getService().getGrantedUriPermissions(packageName, UserHandle.myUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2606,7 +2600,7 @@ public class ActivityManager { */ public void clearGrantedUriPermissions(String packageName) { try { - ActivityManagerNative.getDefault().clearGrantedUriPermissions(packageName, + getService().clearGrantedUriPermissions(packageName, UserHandle.myUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2727,7 +2721,7 @@ public class ActivityManager { */ public List<ProcessErrorStateInfo> getProcessesInErrorState() { try { - return ActivityManagerNative.getDefault().getProcessesInErrorState(); + return getService().getProcessesInErrorState(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2890,6 +2884,29 @@ public class ActivityManager { } } + /** @hide */ + public static int importanceToProcState(int importance) { + if (importance == IMPORTANCE_GONE) { + return PROCESS_STATE_NONEXISTENT; + } else if (importance >= IMPORTANCE_BACKGROUND) { + return PROCESS_STATE_HOME; + } else if (importance >= IMPORTANCE_SERVICE) { + return PROCESS_STATE_SERVICE; + } else if (importance > IMPORTANCE_CANT_SAVE_STATE) { + return PROCESS_STATE_HEAVY_WEIGHT; + } else if (importance >= IMPORTANCE_PERCEPTIBLE) { + return PROCESS_STATE_IMPORTANT_BACKGROUND; + } else if (importance >= IMPORTANCE_VISIBLE) { + return PROCESS_STATE_IMPORTANT_FOREGROUND; + } else if (importance >= IMPORTANCE_TOP_SLEEPING) { + return PROCESS_STATE_TOP_SLEEPING; + } else if (importance >= IMPORTANCE_FOREGROUND_SERVICE) { + return PROCESS_STATE_FOREGROUND_SERVICE; + } else { + return PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } + } + /** * The relative importance level that the system places on this * process. May be one of {@link #IMPORTANCE_FOREGROUND}, @@ -3041,7 +3058,7 @@ public class ActivityManager { */ public List<ApplicationInfo> getRunningExternalApplications() { try { - return ActivityManagerNative.getDefault().getRunningExternalApplications(); + return getService().getRunningExternalApplications(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3057,7 +3074,7 @@ public class ActivityManager { */ public boolean setProcessMemoryTrimLevel(String process, int userId, int level) { try { - return ActivityManagerNative.getDefault().setProcessMemoryTrimLevel(process, userId, + return getService().setProcessMemoryTrimLevel(process, userId, level); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3076,7 +3093,7 @@ public class ActivityManager { */ public List<RunningAppProcessInfo> getRunningAppProcesses() { try { - return ActivityManagerNative.getDefault().getRunningAppProcesses(); + return getService().getRunningAppProcesses(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3146,10 +3163,12 @@ public class ActivityManager { throw new IllegalArgumentException("Listener already registered: " + listener); } // TODO: implement the cut point in the system process to avoid IPCs. - UidObserver observer = new UidObserver(listener, importanceCutpoint); + UidObserver observer = new UidObserver(listener); try { getService().registerUidObserver(observer, - UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE, mContext.getOpPackageName()); + UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE, + RunningAppProcessInfo.importanceToProcState(importanceCutpoint), + mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3192,7 +3211,7 @@ public class ActivityManager { */ static public void getMyMemoryState(RunningAppProcessInfo outState) { try { - ActivityManagerNative.getDefault().getMyMemoryState(outState); + getService().getMyMemoryState(outState); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3211,7 +3230,7 @@ public class ActivityManager { */ public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) { try { - return ActivityManagerNative.getDefault().getProcessMemoryInfo(pids); + return getService().getProcessMemoryInfo(pids); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3244,7 +3263,7 @@ public class ActivityManager { */ public void killBackgroundProcesses(String packageName) { try { - ActivityManagerNative.getDefault().killBackgroundProcesses(packageName, + getService().killBackgroundProcesses(packageName, UserHandle.myUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3262,7 +3281,7 @@ public class ActivityManager { @RequiresPermission(Manifest.permission.KILL_UID) public void killUid(int uid, String reason) { try { - ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid), + getService().killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid), reason); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3290,7 +3309,7 @@ public class ActivityManager { */ public void forceStopPackageAsUser(String packageName, int userId) { try { - ActivityManagerNative.getDefault().forceStopPackage(packageName, userId); + getService().forceStopPackage(packageName, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3309,7 +3328,7 @@ public class ActivityManager { */ public ConfigurationInfo getDeviceConfigurationInfo() { try { - return ActivityManagerNative.getDefault().getDeviceConfigurationInfo(); + return getService().getDeviceConfigurationInfo(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3399,7 +3418,7 @@ public class ActivityManager { */ public static boolean isUserAMonkey() { try { - return ActivityManagerNative.getDefault().isUserAMonkey(); + return getService().isUserAMonkey(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3521,7 +3540,7 @@ public class ActivityManager { return userId; } try { - return ActivityManagerNative.getDefault().handleIncomingUser(callingPid, + return getService().handleIncomingUser(callingPid, callingUid, userId, allowAll, requireFull, name, callerPackage); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3536,7 +3555,7 @@ public class ActivityManager { public static int getCurrentUser() { UserInfo ui; try { - ui = ActivityManagerNative.getDefault().getCurrentUser(); + ui = getService().getCurrentUser(); return ui != null ? ui.id : 0; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3549,7 +3568,7 @@ public class ActivityManager { */ public boolean switchUser(int userid) { try { - return ActivityManagerNative.getDefault().switchUser(userid); + return getService().switchUser(userid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3564,8 +3583,8 @@ public class ActivityManager { int currentUser = ActivityManager.getCurrentUser(); if (currentUser != UserHandle.USER_SYSTEM) { try { - ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM); - ActivityManagerNative.getDefault().stopUser(currentUser, /* force= */ false, null); + getService().switchUser(UserHandle.USER_SYSTEM); + getService().stopUser(currentUser, /* force= */ false, null); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -3587,12 +3606,12 @@ public class ActivityManager { * allowed to run code through scheduled alarms, receiving broadcasts, * etc. A started user may be either the current foreground user or a * background user; the result here does not distinguish between the two. - * @param userid the user's id. Zero indicates the default user. + * @param userId the user's id. Zero indicates the default user. * @hide */ public boolean isUserRunning(int userId) { try { - return ActivityManagerNative.getDefault().isUserRunning(userId, 0); + return getService().isUserRunning(userId, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3601,7 +3620,7 @@ public class ActivityManager { /** {@hide} */ public boolean isVrModePackageEnabled(ComponentName component) { try { - return ActivityManagerNative.getDefault().isVrModePackageEnabled(component); + return getService().isVrModePackageEnabled(component); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3646,6 +3665,23 @@ public class ActivityManager { /** * @hide */ + public static boolean isSystemReady() { + if (!sSystemReady) { + if (ActivityThread.isSystem()) { + sSystemReady = + LocalServices.getService(ActivityManagerInternal.class).isSystemReady(); + } else { + // Since this is being called from outside system server, system should be + // ready by now. + sSystemReady = true; + } + } + return sSystemReady; + } + + /** + * @hide + */ public static void broadcastStickyIntent(Intent intent, int userId) { broadcastStickyIntent(intent, AppOpsManager.OP_NONE, userId); } @@ -3755,7 +3791,7 @@ public class ActivityManager { */ public void setWatchHeapLimit(long pssSize) { try { - ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize, + getService().setDumpHeapDebugLimit(null, 0, pssSize, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3775,7 +3811,7 @@ public class ActivityManager { */ public void clearWatchHeapLimit() { try { - ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null); + getService().setDumpHeapDebugLimit(null, 0, 0, null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3786,7 +3822,7 @@ public class ActivityManager { */ public void startLockTaskMode(int taskId) { try { - ActivityManagerNative.getDefault().startLockTaskModeById(taskId); + getService().startLockTaskModeById(taskId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3797,7 +3833,7 @@ public class ActivityManager { */ public void stopLockTaskMode() { try { - ActivityManagerNative.getDefault().stopLockTaskMode(); + getService().stopLockTaskMode(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3825,7 +3861,7 @@ public class ActivityManager { */ public int getLockTaskModeState() { try { - return ActivityManagerNative.getDefault().getLockTaskModeState(); + return getService().getLockTaskModeState(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3843,7 +3879,7 @@ public class ActivityManager { */ public static void setVrThread(int tid) { try { - ActivityManagerNative.getDefault().setVrThread(tid); + getService().setVrThread(tid); } catch (RemoteException e) { // pass } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index e56fe0f20982..bfa6d349a9f6 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -61,6 +61,11 @@ public abstract class ActivityManagerInternal { */ public static final int APP_TRANSITION_TIMEOUT = 3; + /** + * Verify that calling app has access to the given provider. + */ + public abstract String checkContentProviderAccess(String authority, int userId); + // Called by the power manager. public abstract void onWakefulnessChanged(int wakefulness); @@ -194,4 +199,9 @@ public abstract class ActivityManagerInternal { * @return {@code true} if system is ready, {@code false} otherwise. */ public abstract boolean isSystemReady(); + + /** + * Called when the trusted state of Keyguard has changed. + */ + public abstract void notifyKeyguardTrustedChanged(); } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 10f0425cbdc4..c09403c29943 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -17,7 +17,6 @@ package android.app; import android.content.Intent; import android.os.IBinder; -import com.android.server.LocalServices; /** * {@hide} @@ -50,14 +49,9 @@ public abstract class ActivityManagerNative { * @deprecated use ActivityManagerInternal.isSystemReady instead. */ static public boolean isSystemReady() { - if (!sSystemReady) { - sSystemReady = LocalServices.getService(ActivityManagerInternal.class).isSystemReady(); - } - return sSystemReady; + return ActivityManager.isSystemReady(); } - static volatile boolean sSystemReady = false; - /** * @deprecated use ActivityManager.broadcastStickyIntent instead. */ @@ -97,4 +91,4 @@ public abstract class ActivityManagerNative { static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) { ActivityManager.noteAlarmFinish(ps, sourceUid, tag); } -}
\ No newline at end of file +} diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index d9a46903ee38..1e7f4f04582d 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -18,6 +18,7 @@ package android.app; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.view.Display.INVALID_DISPLAY; import android.annotation.Nullable; import android.annotation.TestApi; @@ -152,6 +153,12 @@ public class ActivityOptions { private static final String KEY_ANIM_SPECS = "android:activity.animSpecs"; /** + * The display id the activity should be launched into. + * @hide + */ + private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId"; + + /** * The stack id the activity should be launched into. * @hide */ @@ -240,6 +247,7 @@ public class ActivityOptions { private int mResultCode; private int mExitCoordinatorIndex; private PendingIntent mUsageTimeReport; + private int mLaunchDisplayId = INVALID_DISPLAY; private int mLaunchStackId = INVALID_STACK_ID; private int mLaunchTaskId = -1; private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; @@ -850,6 +858,7 @@ public class ActivityOptions { mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX); break; } + mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY); mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID); mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1); mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false); @@ -1015,6 +1024,25 @@ public class ActivityOptions { } } + /** + * Gets the id of the display where activity should be launched. + * @return The id of the display where activity should be launched, + * {@link android.view.Display#INVALID_DISPLAY} if not set. + */ + public int getLaunchDisplayId() { + return mLaunchDisplayId; + } + + /** + * Sets the id of the display where activity should be launched. + * @param launchDisplayId The id of the display where the activity should be launched. + * @return {@code this} {@link ActivityOptions} instance. + */ + public ActivityOptions setLaunchDisplayId(int launchDisplayId) { + mLaunchDisplayId = launchDisplayId; + return this; + } + /** @hide */ public int getLaunchStackId() { return mLaunchStackId; @@ -1209,6 +1237,7 @@ public class ActivityOptions { b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex); break; } + b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId); b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId); b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId); b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3e8d90bf62ed..f052bf7fb717 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -80,9 +80,16 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.TransactionTooLargeException; import android.os.UserHandle; +import android.provider.BlockedNumberContract; +import android.provider.CalendarContract; +import android.provider.CallLog; +import android.provider.ContactsContract; +import android.provider.Downloads; import android.provider.Settings; import android.security.NetworkSecurityPolicy; import android.security.net.config.NetworkSecurityConfigProvider; +import android.service.autofill.IAutoFillCallback; +import android.service.voice.VoiceInteractionSession; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.DisplayMetrics; @@ -1302,8 +1309,19 @@ public final class ActivityThread { } @Override - public final void updateTimePrefs(boolean is24Hour) { - DateFormat.set24HourTimePref(is24Hour); + public final void updateTimePrefs(int timeFormatPreference) { + final Boolean timeFormatPreferenceBool; + // For convenience we are using the Intent extra values. + if (timeFormatPreference == Intent.EXTRA_TIME_PREF_VALUE_USE_12_HOUR) { + timeFormatPreferenceBool = Boolean.FALSE; + } else if (timeFormatPreference == Intent.EXTRA_TIME_PREF_VALUE_USE_24_HOUR) { + timeFormatPreferenceBool = Boolean.TRUE; + } else { + // timeFormatPreference == Intent.EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT + // (or unknown). + timeFormatPreferenceBool = null; + } + DateFormat.set24HourTimePref(timeFormatPreferenceBool); } @Override @@ -1793,7 +1811,7 @@ public final class ActivityThread { } if (a != null) { mNewActivities = null; - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); ActivityClientRecord prev; do { if (localLOGV) Slog.v( @@ -2705,7 +2723,7 @@ public final class ActivityThread { private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { int displayId = Display.DEFAULT_DISPLAY; try { - displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token); + displayId = ActivityManager.getService().getActivityDisplayId(r.token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2785,7 +2803,7 @@ public final class ActivityThread { } else { // If there was an error, for any reason, tell the activity manager to stop us. try { - ActivityManagerNative.getDefault() + ActivityManager.getService() .finishActivity(r.token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { @@ -2815,7 +2833,7 @@ public final class ActivityThread { } } try { - ActivityManagerNative.getDefault().reportSizeConfigurations(r.token, + ActivityManager.getService().reportSizeConfigurations(r.token, horizontal.copyKeys(), vertical.copyKeys(), smallest.copyKeys()); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); @@ -2876,16 +2894,24 @@ public final class ActivityThread { mLastAssistStructures.remove(i); } } + // Filling for auto-fill has a few differences: + // - it does not need an AssistContent + // - it does not call onProvideAssistData() + // - it needs an IAutoFillCallback + boolean forAutofill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTOFILL; + Bundle data = new Bundle(); AssistStructure structure = null; - AssistContent content = new AssistContent(); + AssistContent content = forAutofill ? null : new AssistContent(); ActivityClientRecord r = mActivities.get(cmd.activityToken); Uri referrer = null; if (r != null) { r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data); - r.activity.onProvideAssistData(data); + if (!forAutofill) { + r.activity.onProvideAssistData(data); + } referrer = r.activity.onProvideReferrer(); - if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL) { + if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) { structure = new AssistStructure(r.activity); Intent activityIntent = r.activity.getIntent(); if (activityIntent != null && (r.window == null || @@ -2895,18 +2921,28 @@ public final class ActivityThread { intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)); intent.removeUnsafeExtras(); - content.setDefaultIntent(intent); + if (forAutofill) { + IAutoFillCallback autoFillCallback = r.activity.getAutoFillCallback(); + data.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK, + autoFillCallback.asBinder()); + } else { + content.setDefaultIntent(intent); + } } else { - content.setDefaultIntent(new Intent()); + if (!forAutofill) { + content.setDefaultIntent(new Intent()); + } + } + if (!forAutofill) { + r.activity.onProvideAssistContent(content); } - r.activity.onProvideAssistContent(content); } } if (structure == null) { structure = new AssistStructure(); } mLastAssistStructures.add(new WeakReference<>(structure)); - IActivityManager mgr = ActivityManagerNative.getDefault(); + IActivityManager mgr = ActivityManager.getService(); try { mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content, referrer); } catch (RemoteException e) { @@ -2945,7 +2981,7 @@ public final class ActivityThread { } } try { - ActivityManagerNative.getDefault().backgroundResourcesReleased(token); + ActivityManager.getService().backgroundResourcesReleased(token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3044,7 +3080,7 @@ public final class ActivityThread { LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); - IActivityManager mgr = ActivityManagerNative.getDefault(); + IActivityManager mgr = ActivityManager.getService(); BroadcastReceiver receiver; try { @@ -3170,7 +3206,7 @@ public final class ActivityThread { // tell the OS that we're live now try { - ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder); + ActivityManager.getService().backupAgentCreated(packageName, binder); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3227,11 +3263,11 @@ public final class ActivityThread { Application app = packageInfo.makeApplication(false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, - ActivityManagerNative.getDefault()); + ActivityManager.getService()); service.onCreate(); mServices.put(data.token, service); try { - ActivityManagerNative.getDefault().serviceDoneExecuting( + ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3256,11 +3292,11 @@ public final class ActivityThread { try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); - ActivityManagerNative.getDefault().publishService( + ActivityManager.getService().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); - ActivityManagerNative.getDefault().serviceDoneExecuting( + ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } ensureJitEnabled(); @@ -3286,10 +3322,10 @@ public final class ActivityThread { boolean doRebind = s.onUnbind(data.intent); try { if (doRebind) { - ActivityManagerNative.getDefault().unbindFinished( + ActivityManager.getService().unbindFinished( data.token, data.intent, doRebind); } else { - ActivityManagerNative.getDefault().serviceDoneExecuting( + ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } } catch (RemoteException ex) { @@ -3372,7 +3408,7 @@ public final class ActivityThread { QueuedWork.waitToFinish(); try { - ActivityManagerNative.getDefault().serviceDoneExecuting( + ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_START, data.startId, res); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3403,7 +3439,7 @@ public final class ActivityThread { QueuedWork.waitToFinish(); try { - ActivityManagerNative.getDefault().serviceDoneExecuting( + ActivityManager.getService().serviceDoneExecuting( token, SERVICE_DONE_EXECUTING_STOP, 0, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3525,7 +3561,7 @@ public final class ActivityThread { boolean willBeVisible = !a.mStartedActivity; if (!willBeVisible) { try { - willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible( + willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -3613,7 +3649,7 @@ public final class ActivityThread { // Tell the activity manager we have resumed. if (reallyResume) { try { - ActivityManagerNative.getDefault().activityResumed(token); + ActivityManager.getService().activityResumed(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -3623,7 +3659,7 @@ public final class ActivityThread { // If an exception was thrown when trying to resume, then // just end this activity. try { - ActivityManagerNative.getDefault() + ActivityManager.getService() .finishActivity(token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { @@ -3712,7 +3748,7 @@ public final class ActivityThread { // Tell the activity manager we have paused. if (!dontReport) { try { - ActivityManagerNative.getDefault().activityPaused(token); + ActivityManager.getService().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -3810,7 +3846,7 @@ public final class ActivityThread { // Tell activity manager we have been stopped. try { if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity); - ActivityManagerNative.getDefault().activityStopped( + ActivityManager.getService().activityStopped( activity.token, state, persistentState, description); } catch (RemoteException ex) { if (ex instanceof TransactionTooLargeException @@ -4065,7 +4101,7 @@ public final class ActivityThread { // Tell activity manager we slept. try { - ActivityManagerNative.getDefault().activitySlept(r.token); + ActivityManager.getService().activitySlept(r.token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -4319,7 +4355,7 @@ public final class ActivityThread { } if (finishing) { try { - ActivityManagerNative.getDefault().activityDestroyed(token); + ActivityManager.getService().activityDestroyed(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -4361,7 +4397,7 @@ public final class ActivityThread { // For each relaunch request, activity manager expects an answer if (!r.onlyLocalRequest && fromServer) { try { - ActivityManagerNative.getDefault().activityRelaunched(token); + ActivityManager.getService().activityRelaunched(token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4487,7 +4523,7 @@ public final class ActivityThread { if (r == null) { if (!tmp.onlyLocalRequest) { try { - ActivityManagerNative.getDefault().activityRelaunched(tmp.token); + ActivityManager.getService().activityRelaunched(tmp.token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4560,7 +4596,7 @@ public final class ActivityThread { if (!tmp.onlyLocalRequest) { try { - ActivityManagerNative.getDefault().activityRelaunched(r.token); + ActivityManager.getService().activityRelaunched(r.token); if (r.window != null) { r.window.reportActivityRelaunched(); } @@ -4925,7 +4961,7 @@ public final class ActivityThread { Debug.dumpNativeHeap(dhd.fd.getFileDescriptor()); } try { - ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path); + ActivityManager.getService().dumpHeapFinished(dhd.path); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -5217,7 +5253,14 @@ public final class ActivityThread { } updateDefaultDensity(); - final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24)); + final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24); + Boolean is24Hr = null; + if (use24HourSetting != null) { + is24Hr = "24".equals(use24HourSetting) ? Boolean.TRUE : Boolean.FALSE; + } + // null : use locale default for 12/24 hour formatting, + // false : use 12 hour format, + // true : use 24 hour format. DateFormat.set24HourTimePref(is24Hr); View.mDebugViewAttributes = @@ -5269,7 +5312,7 @@ public final class ActivityThread { Slog.w(TAG, "Application " + data.info.getPackageName() + " is waiting for the debugger on port 8100..."); - IActivityManager mgr = ActivityManagerNative.getDefault(); + IActivityManager mgr = ActivityManager.getService(); try { mgr.showWaitingForDebugger(mAppThread, true); } catch (RemoteException ex) { @@ -5463,12 +5506,12 @@ public final class ActivityThread { } /*package*/ final void finishInstrumentation(int resultCode, Bundle results) { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (mProfiler.profileFile != null && mProfiler.handlingProfiling && mProfiler.profileFd == null) { Debug.stopMethodTracing(); } - //Slog.i(TAG, "am: " + ActivityManagerNative.getDefault() + //Slog.i(TAG, "am: " + ActivityManager.getService() // + ", app thr: " + mAppThread); try { am.finishInstrumentation(mAppThread, resultCode, results); @@ -5499,7 +5542,7 @@ public final class ActivityThread { } try { - ActivityManagerNative.getDefault().publishContentProviders( + ActivityManager.getService().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); @@ -5521,7 +5564,7 @@ public final class ActivityThread { // be re-entrant in the case where the provider is in the same process. ContentProviderHolder holder = null; try { - holder = ActivityManagerNative.getDefault().getContentProvider( + holder = ActivityManager.getService().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); @@ -5567,7 +5610,7 @@ public final class ActivityThread { + prc.holder.info.name + ": unstableDelta=" + unstableDelta); } - ActivityManagerNative.getDefault().refContentProvider( + ActivityManager.getService().refContentProvider( prc.holder.connection, 1, unstableDelta); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5596,7 +5639,7 @@ public final class ActivityThread { Slog.v(TAG, "incProviderRef: Now unstable - " + prc.holder.info.name); } - ActivityManagerNative.getDefault().refContentProvider( + ActivityManager.getService().refContentProvider( prc.holder.connection, 0, 1); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5670,7 +5713,7 @@ public final class ActivityThread { Slog.v(TAG, "releaseProvider: No longer stable w/lastRef=" + lastRef + " - " + prc.holder.info.name); } - ActivityManagerNative.getDefault().refContentProvider( + ActivityManager.getService().refContentProvider( prc.holder.connection, -1, lastRef ? 1 : 0); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5694,7 +5737,7 @@ public final class ActivityThread { Slog.v(TAG, "releaseProvider: No longer unstable - " + prc.holder.info.name); } - ActivityManagerNative.getDefault().refContentProvider( + ActivityManager.getService().refContentProvider( prc.holder.connection, 0, -1); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5758,10 +5801,10 @@ public final class ActivityThread { try { if (DEBUG_PROVIDER) { - Slog.v(TAG, "removeProvider: Invoking ActivityManagerNative." + Slog.v(TAG, "removeProvider: Invoking ActivityManagerService." + "removeContentProvider(" + prc.holder.info.name + ")"); } - ActivityManagerNative.getDefault().removeContentProvider( + ActivityManager.getService().removeContentProvider( prc.holder.connection, false); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5795,7 +5838,7 @@ public final class ActivityThread { // it knows it is dead (so we don't race with its death // notification). try { - ActivityManagerNative.getDefault().unstableProviderDied( + ActivityManager.getService().unstableProviderDied( prc.holder.connection); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5809,7 +5852,7 @@ public final class ActivityThread { ProviderRefCount prc = mProviderRefCountMap.get(provider); if (prc != null) { try { - ActivityManagerNative.getDefault() + ActivityManager.getService() .appNotRespondingViaProvider(prc.holder.connection); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -5823,6 +5866,23 @@ public final class ActivityThread { final String auths[] = holder.info.authority.split(";"); final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid); + if (provider != null) { + // If this provider is hosted by the core OS and cannot be upgraded, + // then I guess we're okay doing blocking calls to it. + for (String auth : auths) { + switch (auth) { + case ContactsContract.AUTHORITY: + case CallLog.AUTHORITY: + case CallLog.SHADOW_AUTHORITY: + case BlockedNumberContract.AUTHORITY: + case CalendarContract.AUTHORITY: + case Downloads.Impl.AUTHORITY: + case "telephony": + Binder.allowBlocking(provider.asBinder()); + } + } + } + final ProviderClientRecord pcr = new ProviderClientRecord( auths, provider, localProvider, holder); for (String auth : auths) { @@ -5950,7 +6010,7 @@ public final class ActivityThread { if (!noReleaseNeeded) { incProviderRefLocked(prc, stable); try { - ActivityManagerNative.getDefault().removeContentProvider( + ActivityManager.getService().removeContentProvider( holder.connection, stable); } catch (RemoteException e) { //do nothing content provider object is dead any way @@ -5971,7 +6031,6 @@ public final class ActivityThread { retHolder = prc.holder; } } - return retHolder; } @@ -5988,7 +6047,7 @@ public final class ActivityThread { android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId()); RuntimeInit.setApplicationObject(mAppThread.asBinder()); - final IActivityManager mgr = ActivityManagerNative.getDefault(); + final IActivityManager mgr = ActivityManager.getService(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index ec21882f431e..af41db01418e 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -37,6 +37,8 @@ import android.view.ViewTreeObserver; import android.view.Window; import android.widget.ImageView; +import com.android.internal.view.OneShotPreDrawListener; + import java.util.ArrayList; import java.util.Collection; @@ -570,16 +572,9 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) { final View decorView = getDecor(); if (decorView != null) { - decorView.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); - notifySharedElementEnd(snapshots); - return true; - } - } - ); + OneShotPreDrawListener.add(decorView, () -> { + notifySharedElementEnd(snapshots); + }); } } @@ -816,6 +811,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { if (moveWithParent && !isInTransitionGroup(parent, decor)) { GhostViewListeners listener = new GhostViewListeners(view, parent, decor); parent.getViewTreeObserver().addOnPreDrawListener(listener); + parent.addOnAttachStateChangeListener(listener); mGhostViewListeners.add(listener); } } @@ -842,8 +838,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { int numListeners = mGhostViewListeners.size(); for (int i = 0; i < numListeners; i++) { GhostViewListeners listener = mGhostViewListeners.get(i); - ViewGroup parent = (ViewGroup) listener.getView().getParent(); - parent.getViewTreeObserver().removeOnPreDrawListener(listener); + listener.removeListener(); } mGhostViewListeners.clear(); @@ -874,15 +869,9 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected void scheduleGhostVisibilityChange(final int visibility) { final View decorView = getDecor(); if (decorView != null) { - decorView.getViewTreeObserver() - .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); - setGhostVisibility(visibility); - return true; - } - }); + OneShotPreDrawListener.add(decorView, () -> { + setGhostVisibility(visibility); + }); } } @@ -988,16 +977,19 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } - private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener { + private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener, + View.OnAttachStateChangeListener { private View mView; private ViewGroup mDecor; private View mParent; private Matrix mMatrix = new Matrix(); + private ViewTreeObserver mViewTreeObserver; public GhostViewListeners(View view, View parent, ViewGroup decor) { mView = view; mParent = parent; mDecor = decor; + mViewTreeObserver = parent.getViewTreeObserver(); } public View getView() { @@ -1008,13 +1000,32 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { public boolean onPreDraw() { GhostView ghostView = GhostView.getGhost(mView); if (ghostView == null) { - mParent.getViewTreeObserver().removeOnPreDrawListener(this); + removeListener(); } else { GhostView.calculateMatrix(mView, mDecor, mMatrix); ghostView.setMatrix(mMatrix); } return true; } + + public void removeListener() { + if (mViewTreeObserver.isAlive()) { + mViewTreeObserver.removeOnPreDrawListener(this); + } else { + mParent.getViewTreeObserver().removeOnPreDrawListener(this); + } + mParent.removeOnAttachStateChangeListener(this); + } + + @Override + public void onViewAttachedToWindow(View v) { + mViewTreeObserver = v.getViewTreeObserver(); + } + + @Override + public void onViewDetachedFromWindow(View v) { + removeListener(); + } } static class SharedElementOriginalState { diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java index 60046b5932ee..f2616ffa2465 100644 --- a/core/java/android/app/ActivityTransitionState.java +++ b/core/java/android/app/ActivityTransitionState.java @@ -22,9 +22,10 @@ import android.transition.Transition; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.Window; +import com.android.internal.view.OneShotPreDrawListener; + import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -321,18 +322,12 @@ class ActivityTransitionState { } if (delayExitBack && decor != null) { final ViewGroup finalDecor = decor; - decor.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - finalDecor.getViewTreeObserver().removeOnPreDrawListener(this); - if (mReturnExitCoordinator != null) { - mReturnExitCoordinator.startExit(activity.mResultCode, - activity.mResultData); - } - return true; - } - }); + OneShotPreDrawListener.add(decor, () -> { + if (mReturnExitCoordinator != null) { + mReturnExitCoordinator.startExit(activity.mResultCode, + activity.mResultData); + } + }); } else { mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData); } diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index cada1b854a8e..29b83dc3b315 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -152,7 +152,7 @@ public class ActivityView extends ViewGroup { try { mActivityContainer = new ActivityContainerWrapper( - ActivityManagerNative.getDefault().createVirtualActivityContainer( + ActivityManager.getService().createVirtualActivityContainer( mActivity.getActivityToken(), new ActivityContainerCallback(this))); } catch (RemoteException e) { throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " diff --git a/core/java/android/app/AppImportanceMonitor.java b/core/java/android/app/AppImportanceMonitor.java index e0d0d8d77778..b5cbeeb0d729 100644 --- a/core/java/android/app/AppImportanceMonitor.java +++ b/core/java/android/app/AppImportanceMonitor.java @@ -86,7 +86,7 @@ public class AppImportanceMonitor { }; ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); try { - ActivityManagerNative.getDefault().registerProcessObserver(mProcessObserver); + ActivityManager.getService().registerProcessObserver(mProcessObserver); } catch (RemoteException e) { } List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 191cc4944e26..ba6bc159cdf2 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -240,7 +240,9 @@ public class AppOpsManager { /** @hide Control whether an application is allowed to run in the background. */ public static final int OP_RUN_IN_BACKGROUND = 63; /** @hide */ - public static final int _NUM_OP = 64; + public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = 64; + /** @hide */ + public static final int _NUM_OP = 65; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -452,6 +454,7 @@ public class AppOpsManager { OP_TURN_SCREEN_ON, OP_GET_ACCOUNTS, OP_RUN_IN_BACKGROUND, + OP_AUDIO_ACCESSIBILITY_VOLUME, }; /** @@ -523,6 +526,7 @@ public class AppOpsManager { null, OPSTR_GET_ACCOUNTS, null, + null, // OP_AUDIO_ACCESSIBILITY_VOLUME }; /** @@ -594,6 +598,7 @@ public class AppOpsManager { "TURN_ON_SCREEN", "GET_ACCOUNTS", "RUN_IN_BACKGROUND", + "AUDIO_ACCESSIBILITY_VOLUME", }; /** @@ -665,6 +670,7 @@ public class AppOpsManager { null, // no permission for turning the screen on Manifest.permission.GET_ACCOUNTS, null, // no permission for running in background + null, // no permission for changing accessibility volume }; /** @@ -737,6 +743,7 @@ public class AppOpsManager { null, // TURN_ON_SCREEN null, // GET_ACCOUNTS null, // RUN_IN_BACKGROUND + UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME }; /** @@ -808,6 +815,7 @@ public class AppOpsManager { false, // TURN_ON_SCREEN false, // GET_ACCOUNTS false, // RUN_IN_BACKGROUND + false, // AUDIO_ACCESSIBILITY_VOLUME }; /** @@ -878,6 +886,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND + AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ACCESSIBILITY_VOLUME }; /** @@ -952,6 +961,7 @@ public class AppOpsManager { false, false, false, + false, // OP_AUDIO_ACCESSIBILITY_VOLUME }; /** diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 6a73829da154..ef2db4a0d795 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -16,17 +16,19 @@ package android.app; +import android.os.Build; import android.os.Trace; import android.util.ArrayMap; import com.android.internal.os.PathClassLoaderFactory; import dalvik.system.PathClassLoader; -class ApplicationLoaders { +/** @hide */ +public class ApplicationLoaders { public static ApplicationLoaders getDefault() { return gApplicationLoaders; } - public ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, + ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent) { /* @@ -80,6 +82,19 @@ class ApplicationLoaders { } } + /** + * Creates a classloader for the WebView APK and places it in the cache of loaders maintained + * by this class. This is used in the WebView zygote, where its presence in the cache speeds up + * startup and enables memory sharing. + */ + public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath) { + // The correct paths are calculated by WebViewZygote in the system server and passed to + // us here. We hardcode the other parameters: WebView always targets the current SDK, + // does not need to use non-public system libraries, and uses the base classloader as its + // parent to permit usage of the cache. + return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null); + } + private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath); /** 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/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index cf794c5b410e..e222fee6e409 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -349,7 +349,9 @@ final class BackStackRecord extends FragmentTransaction implements public BackStackRecord(FragmentManagerImpl manager) { mManager = manager; - mAllowOptimization = Build.isAtLeastO(); + int targetSdkVersion = manager.mHost.getContext().getApplicationInfo().targetSdkVersion; + // TODO: make the check N_MR1 or O + mAllowOptimization = targetSdkVersion > Build.VERSION_CODES.N; } public int getId() { @@ -762,7 +764,7 @@ final class BackStackRecord extends FragmentTransaction implements } if (!mAllowOptimization) { // Added fragments are added at the end to comply with prior behavior. - mManager.moveToState(mManager.mCurState); + mManager.moveToState(mManager.mCurState, true); } } @@ -808,7 +810,7 @@ final class BackStackRecord extends FragmentTransaction implements } } if (!mAllowOptimization) { - mManager.moveToState(mManager.mCurState); + mManager.moveToState(mManager.mCurState, true); } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index f1d0e10dd6e3..827e02696e2b 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -18,6 +18,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; @@ -60,7 +61,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -797,7 +798,7 @@ class ContextImpl extends Context { @Override public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) { try { - ActivityManagerNative.getDefault().startActivityAsUser( + ActivityManager.getService().startActivityAsUser( mMainThread.getApplicationThread(), getBasePackageName(), intent, intent.resolveTypeIfNeeded(getContentResolver()), null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, @@ -859,7 +860,7 @@ class ContextImpl extends Context { fillInIntent.prepareToLeaveProcess(this); resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver()); } - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivityIntentSender(mMainThread.getApplicationThread(), intent, fillInIntent, resolvedType, null, null, 0, flagsMask, flagsValues, options); @@ -878,7 +879,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); @@ -895,7 +896,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, null, false, false, getUserId()); @@ -910,7 +911,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, null, false, false, getUserId()); @@ -927,7 +928,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, options, false, false, getUserId()); @@ -944,7 +945,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false, getUserId()); @@ -961,7 +962,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, null, true, false, getUserId()); @@ -1024,7 +1025,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, receiverPermissions, appOp, options, true, false, getUserId()); @@ -1038,7 +1039,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), + ActivityManager.getService().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, user.getIdentifier()); } catch (RemoteException e) { @@ -1060,7 +1061,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, options, false, false, user.getIdentifier()); @@ -1077,7 +1078,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false, user.getIdentifier()); @@ -1128,7 +1129,7 @@ class ContextImpl extends Context { : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, receiverPermissions, appOp, options, true, false, user.getIdentifier()); @@ -1144,7 +1145,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, getUserId()); @@ -1180,7 +1181,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null, true, true, getUserId()); @@ -1199,7 +1200,7 @@ class ContextImpl extends Context { } try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().unbroadcastIntent( + ActivityManager.getService().unbroadcastIntent( mMainThread.getApplicationThread(), intent, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1212,7 +1213,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier()); @@ -1227,7 +1228,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true, user.getIdentifier()); @@ -1262,7 +1263,7 @@ class ContextImpl extends Context { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().broadcastIntent( + ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null, true, true, user.getIdentifier()); @@ -1281,7 +1282,7 @@ class ContextImpl extends Context { } try { intent.prepareToLeaveProcess(this); - ActivityManagerNative.getDefault().unbroadcastIntent( + ActivityManager.getService().unbroadcastIntent( mMainThread.getApplicationThread(), intent, user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1328,7 +1329,7 @@ class ContextImpl extends Context { } } try { - final Intent intent = ActivityManagerNative.getDefault().registerReceiver( + final Intent intent = ActivityManager.getService().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); if (intent != null) { @@ -1347,7 +1348,7 @@ class ContextImpl extends Context { IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher( getOuterContext(), receiver); try { - ActivityManagerNative.getDefault().unregisterReceiver(rd); + ActivityManager.getService().unregisterReceiver(rd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1390,7 +1391,7 @@ class ContextImpl extends Context { try { validateServiceIntent(service); service.prepareToLeaveProcess(this); - ComponentName cn = ActivityManagerNative.getDefault().startService( + ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), getOpPackageName(), user.getIdentifier()); if (cn != null) { @@ -1419,7 +1420,7 @@ class ContextImpl extends Context { try { validateServiceIntent(service); service.prepareToLeaveProcess(this); - int res = ActivityManagerNative.getDefault().stopService( + int res = ActivityManager.getService().stopService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier()); if (res < 0) { @@ -1457,8 +1458,22 @@ class ContextImpl extends Context { return bindServiceCommon(service, conn, flags, handler, user); } + /** @hide */ + @Override + public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler, + int flags) { + return mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); + } + + /** @hide */ + @Override + public IApplicationThread getIApplicationThread() { + return mMainThread.getApplicationThread(); + } + private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) { + // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser. IServiceConnection sd; if (conn == null) { throw new IllegalArgumentException("connection is null"); @@ -1477,7 +1492,7 @@ class ContextImpl extends Context { flags |= BIND_WAIVE_PRIORITY; } service.prepareToLeaveProcess(this); - int res = ActivityManagerNative.getDefault().bindService( + int res = ActivityManager.getService().bindService( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, getOpPackageName(), user.getIdentifier()); @@ -1500,7 +1515,7 @@ class ContextImpl extends Context { IServiceConnection sd = mPackageInfo.forgetServiceDispatcher( getOuterContext(), conn); try { - ActivityManagerNative.getDefault().unbindService(sd); + ActivityManager.getService().unbindService(sd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1516,7 +1531,7 @@ class ContextImpl extends Context { if (arguments != null) { arguments.setAllowFds(false); } - return ActivityManagerNative.getDefault().startInstrumentation( + return ActivityManager.getService().startInstrumentation( className, profileFile, 0, arguments, null, null, getUserId(), null /* ABI override */); } catch (RemoteException e) { @@ -1541,7 +1556,7 @@ class ContextImpl extends Context { } try { - return ActivityManagerNative.getDefault().checkPermission( + return ActivityManager.getService().checkPermission( permission, pid, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1556,7 +1571,7 @@ class ContextImpl extends Context { } try { - return ActivityManagerNative.getDefault().checkPermissionWithToken( + return ActivityManager.getService().checkPermissionWithToken( permission, pid, uid, callerToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1641,7 +1656,7 @@ class ContextImpl extends Context { @Override public void grantUriPermission(String toPackage, Uri uri, int modeFlags) { try { - ActivityManagerNative.getDefault().grantUriPermission( + ActivityManager.getService().grantUriPermission( mMainThread.getApplicationThread(), toPackage, ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { @@ -1652,7 +1667,7 @@ class ContextImpl extends Context { @Override public void revokeUriPermission(Uri uri, int modeFlags) { try { - ActivityManagerNative.getDefault().revokeUriPermission( + ActivityManager.getService().revokeUriPermission( mMainThread.getApplicationThread(), ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { @@ -1663,7 +1678,7 @@ class ContextImpl extends Context { @Override public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { try { - return ActivityManagerNative.getDefault().checkUriPermission( + return ActivityManager.getService().checkUriPermission( ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags, resolveUserId(uri), null); } catch (RemoteException e) { @@ -1675,7 +1690,7 @@ class ContextImpl extends Context { @Override public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) { try { - return ActivityManagerNative.getDefault().checkUriPermission( + return ActivityManager.getService().checkUriPermission( ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags, resolveUserId(uri), callerToken); } catch (RemoteException e) { @@ -2141,7 +2156,8 @@ class ContextImpl extends Context { return mOuterContext; } - final IBinder getActivityToken() { + @Override + public IBinder getActivityToken() { return mActivityToken; } @@ -2197,10 +2213,11 @@ class ContextImpl extends Context { if (!dir.exists()) { // Failing to mkdir() may be okay, since we might not have // enough permissions; ask vold to create on our behalf. - final IMountService mount = IMountService.Stub.asInterface( + final IStorageManager storageManager = IStorageManager.Stub.asInterface( ServiceManager.getService("mount")); try { - final int res = mount.mkdirs(getPackageName(), dir.getAbsolutePath()); + final int res = storageManager.mkdirs( + getPackageName(), dir.getAbsolutePath()); if (res != 0) { Log.w(TAG, "Failed to ensure " + dir + ": " + res); dir = null; diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index 27a02003669d..3464c4d8cbeb 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -30,10 +30,11 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; -import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.Window; import android.view.accessibility.AccessibilityEvent; +import com.android.internal.view.OneShotPreDrawListener; + import java.util.ArrayList; /** @@ -58,7 +59,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private boolean mAreViewsReady; private boolean mIsViewsTransitionStarted; private Transition mEnterViewsTransition; - private OnPreDrawListener mViewsReadyListener; + private OneShotPreDrawListener mViewsReadyListener; private final boolean mIsCrossTask; public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver, @@ -74,12 +75,17 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle); final View decorView = getDecor(); if (decorView != null) { - decorView.getViewTreeObserver().addOnPreDrawListener( + final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver(); + viewTreeObserver.addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (mIsReadyForTransition) { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); + if (viewTreeObserver.isAlive()) { + viewTreeObserver.removeOnPreDrawListener(this); + } else { + decorView.getViewTreeObserver().removeOnPreDrawListener(this); + } } return mIsReadyForTransition; } @@ -147,16 +153,10 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) { viewsReady(sharedElements); } else { - mViewsReadyListener = new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - mViewsReadyListener = null; - decor.getViewTreeObserver().removeOnPreDrawListener(this); - viewsReady(sharedElements); - return true; - } - }; - decor.getViewTreeObserver().addOnPreDrawListener(mViewsReadyListener); + mViewsReadyListener = OneShotPreDrawListener.add(decor, () -> { + mViewsReadyListener = null; + viewsReady(sharedElements); + }); decor.invalidate(); } } @@ -206,19 +206,13 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); } else if (decorView != null) { - decorView.getViewTreeObserver() - .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); - if (mResultReceiver != null) { - Bundle state = captureSharedElementState(); - moveSharedElementsToOverlay(); - mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); - } - return true; - } - }); + OneShotPreDrawListener.add(decorView, () -> { + if (mResultReceiver != null) { + Bundle state = captureSharedElementState(); + moveSharedElementsToOverlay(); + mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); + } + }); } if (allowOverlappingTransitions()) { startEnterTransitionOnly(); @@ -271,7 +265,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { mIsReadyForTransition = true; final ViewGroup decor = getDecor(); if (decor != null && mViewsReadyListener != null) { - decor.getViewTreeObserver().removeOnPreDrawListener(mViewsReadyListener); + mViewsReadyListener.removeListener(); mViewsReadyListener = null; } showViews(mTransitioningViews, true); @@ -457,20 +451,11 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { public void onSharedElementsReady() { final View decorView = getDecor(); if (decorView != null) { - decorView.getViewTreeObserver() - .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); - startTransition(new Runnable() { - @Override - public void run() { - startSharedElementTransition(sharedElementState); - } - }); - return false; - } - }); + OneShotPreDrawListener.add(decorView, () -> { + startTransition(() -> { + startSharedElementTransition(sharedElementState); + }); + }); decorView.invalidate(); } } diff --git a/core/java/android/app/EphemeralResolverService.java b/core/java/android/app/EphemeralResolverService.java index ba791085d617..45652ef7c37d 100644 --- a/core/java/android/app/EphemeralResolverService.java +++ b/core/java/android/app/EphemeralResolverService.java @@ -40,6 +40,7 @@ public abstract class EphemeralResolverService extends Service { public static final String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO"; public static final String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE"; private static final String EXTRA_PREFIX = "android.app.PREFIX"; + private static final String EXTRA_HOSTNAME = "android.app.HOSTNAME"; private Handler mHandler; /** @@ -49,14 +50,41 @@ public abstract class EphemeralResolverService extends Service { * @param prefixMask A mask that was applied to each digest prefix. This should * be used when comparing against the digest prefixes as all bits might * not be set. + * @deprecated use {@link #onGetEphemeralResolveInfo(int[])} instead */ + @Deprecated public abstract List<EphemeralResolveInfo> onEphemeralResolveInfoList( - int digestPrefix[], int prefixMask); + int digestPrefix[], int prefix); + + /** + * Called to retrieve resolve info for ephemeral applications. + * + * @param digestPrefix The hash prefix of the ephemeral's domain. + */ + public List<EphemeralResolveInfo> onGetEphemeralResolveInfo(int digestPrefix[]) { + return onEphemeralResolveInfoList(digestPrefix, 0xFFFFF000); + } + + /** + * Called to retrieve intent filters for ephemeral applications. + * + * @param hostName The name of the host to get intent filters for. + */ + public EphemeralResolveInfo onGetEphemeralIntentFilter(String hostName) { + throw new IllegalStateException("Must define"); + } + + /** + * Returns a {@link Looper} to perform service operations on. + */ + public Looper getLooper() { + return getBaseContext().getMainLooper(); + } @Override public final void attachBaseContext(Context base) { super.attachBaseContext(base); - mHandler = new ServiceHandler(base.getMainLooper()); + mHandler = new ServiceHandler(getLooper()); } @Override @@ -64,19 +92,31 @@ public abstract class EphemeralResolverService extends Service { return new IEphemeralResolver.Stub() { @Override public void getEphemeralResolveInfoList( - IRemoteCallback callback, int digestPrefix[], int prefixMask, int sequence) { + IRemoteCallback callback, int digestPrefix[], int sequence) { final Message msg = mHandler.obtainMessage( - ServiceHandler.MSG_GET_EPHEMERAL_RESOLVE_INFO, prefixMask, sequence, callback); + ServiceHandler.MSG_GET_EPHEMERAL_RESOLVE_INFO, sequence, 0, callback); final Bundle data = new Bundle(); data.putIntArray(EXTRA_PREFIX, digestPrefix); msg.setData(data); msg.sendToTarget(); } + + @Override + public void getEphemeralIntentFilterList( + 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.putString(EXTRA_HOSTNAME, hostName); + msg.setData(data); + msg.sendToTarget(); + } }; } private final class ServiceHandler extends Handler { public static final int MSG_GET_EPHEMERAL_RESOLVE_INFO = 1; + public static final int MSG_GET_EPHEMERAL_INTENT_FILTER = 2; public ServiceHandler(Looper looper) { super(looper, null /*callback*/, true /*async*/); @@ -91,9 +131,9 @@ public abstract class EphemeralResolverService extends Service { final IRemoteCallback callback = (IRemoteCallback) message.obj; final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX); final List<EphemeralResolveInfo> resolveInfo = - onEphemeralResolveInfoList(digestPrefix, message.arg1); + onGetEphemeralResolveInfo(digestPrefix); final Bundle data = new Bundle(); - data.putInt(EXTRA_SEQUENCE, message.arg2); + data.putInt(EXTRA_SEQUENCE, message.arg1); data.putParcelableList(EXTRA_RESOLVE_INFO, resolveInfo); try { callback.sendResult(data); @@ -101,6 +141,19 @@ public abstract class EphemeralResolverService extends Service { } } break; + case MSG_GET_EPHEMERAL_INTENT_FILTER: { + final IRemoteCallback callback = (IRemoteCallback) message.obj; + 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.putParcelable(EXTRA_RESOLVE_INFO, resolveInfo); + try { + callback.sendResult(data); + } catch (RemoteException e) { + } + } break; + default: { throw new IllegalArgumentException("Unknown message: " + action); } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index b5b6e4aa1892..6a79e6cfdf9c 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -34,9 +34,10 @@ import android.transition.Transition; import android.transition.TransitionManager; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.Window; +import com.android.internal.view.OneShotPreDrawListener; + import java.util.ArrayList; /** @@ -168,15 +169,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { }); final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames); - decorView.getViewTreeObserver() - .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decorView.getViewTreeObserver().removeOnPreDrawListener(this); - setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots); - return true; - } - }); + OneShotPreDrawListener.add(decorView, () -> { + setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots); + }); setGhostVisibility(View.INVISIBLE); scheduleGhostVisibilityChange(View.INVISIBLE); if (mListener != null) { diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 8124232bd49e..10ab2bc71590 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -414,6 +414,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // True if this fragment has been restored from previously saved state. boolean mRestored; + // True if performCreateView has been called and a matching call to performDestroyView + // has not yet happened. + boolean mPerformedCreateView; + // Number of active back stack entries this fragment is in. int mBackStackNesting; @@ -611,7 +615,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene Fragment f = (Fragment)clazz.newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); - f.mArguments = args; + f.setArguments(args); } return f; } catch (ClassNotFoundException e) { @@ -2464,6 +2468,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene if (mChildFragmentManager != null) { mChildFragmentManager.noteStateNotSaved(); } + mPerformedCreateView = true; return onCreateView(inflater, container, savedInstanceState); } @@ -2690,6 +2695,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene if (mLoaderManager != null) { mLoaderManager.doReportNextStart(); } + mPerformedCreateView = false; } void performDestroy() { diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 5a2c5e771807..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 @@ -1072,7 +1072,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) { newState = Fragment.STOPPED; } - if (f.mState < newState) { + if (f.mState <= newState) { // For fragments that are created from a layout, when restoring from // state we don't want to allow them to be created until they are // being reloaded from the layout. @@ -1089,65 +1089,59 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } switch (f.mState) { case Fragment.INITIALIZING: - if (DEBUG) Log.v(TAG, "moveto CREATED: " + f); - if (f.mSavedFragmentState != null) { - f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray( - FragmentManagerImpl.VIEW_STATE_TAG); - f.mTarget = getFragment(f.mSavedFragmentState, - FragmentManagerImpl.TARGET_STATE_TAG); - if (f.mTarget != null) { - f.mTargetRequestCode = f.mSavedFragmentState.getInt( - FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0); - } - f.mUserVisibleHint = f.mSavedFragmentState.getBoolean( - FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true); - if (!f.mUserVisibleHint) { - f.mDeferStart = true; - if (newState > Fragment.STOPPED) { - newState = Fragment.STOPPED; + if (newState > Fragment.INITIALIZING) { + if (DEBUG) Log.v(TAG, "moveto CREATED: " + f); + if (f.mSavedFragmentState != null) { + f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray( + FragmentManagerImpl.VIEW_STATE_TAG); + f.mTarget = getFragment(f.mSavedFragmentState, + FragmentManagerImpl.TARGET_STATE_TAG); + if (f.mTarget != null) { + f.mTargetRequestCode = f.mSavedFragmentState.getInt( + FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0); + } + f.mUserVisibleHint = f.mSavedFragmentState.getBoolean( + FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true); + if (!f.mUserVisibleHint) { + f.mDeferStart = true; + if (newState > Fragment.STOPPED) { + newState = Fragment.STOPPED; + } } } - } - f.mHost = mHost; - f.mParentFragment = mParent; - f.mFragmentManager = mParent != null - ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl(); - dispatchOnFragmentPreAttached(f, mHost.getContext(), false); - f.mCalled = false; - f.onAttach(mHost.getContext()); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onAttach()"); - } - if (f.mParentFragment == null) { - mHost.onAttachFragment(f); - } else { - f.mParentFragment.onAttachFragment(f); - } - dispatchOnFragmentAttached(f, mHost.getContext(), false); + f.mHost = mHost; + f.mParentFragment = mParent; + f.mFragmentManager = mParent != null + ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl(); + dispatchOnFragmentPreAttached(f, mHost.getContext(), false); + f.mCalled = false; + f.onAttach(mHost.getContext()); + if (!f.mCalled) { + throw new SuperNotCalledException("Fragment " + f + + " did not call through to super.onAttach()"); + } + if (f.mParentFragment == null) { + mHost.onAttachFragment(f); + } else { + f.mParentFragment.onAttachFragment(f); + } + dispatchOnFragmentAttached(f, mHost.getContext(), false); - if (!f.mRetaining) { - f.performCreate(f.mSavedFragmentState); - dispatchOnFragmentCreated(f, f.mSavedFragmentState, false); - } else { - f.restoreChildFragmentState(f.mSavedFragmentState, true); - f.mState = Fragment.CREATED; - } - f.mRetaining = false; - if (f.mFromLayout) { - // For fragments that are part of the content view - // layout, we need to instantiate the view immediately - // and the inflater will take care of adding it. - f.mView = f.performCreateView(f.getLayoutInflater( - f.mSavedFragmentState), null, f.mSavedFragmentState); - if (f.mView != null) { - f.mView.setSaveFromParentEnabled(false); - if (f.mHidden) f.mView.setVisibility(View.GONE); - f.onViewCreated(f.mView, f.mSavedFragmentState); - dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false); + if (!f.mRetaining) { + f.performCreate(f.mSavedFragmentState); + dispatchOnFragmentCreated(f, f.mSavedFragmentState, false); + } else { + f.restoreChildFragmentState(f.mSavedFragmentState, true); + f.mState = Fragment.CREATED; } + f.mRetaining = false; } case Fragment.CREATED: + // This is outside the if statement below on purpose; we want this to run + // even if we do a moveToState from CREATED => *, CREATED => CREATED, and + // * => CREATED as part of the case fallthrough above. + ensureInflatedFragmentView(f); + if (newState > Fragment.CREATED) { if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f); if (!f.mFromLayout) { @@ -1281,6 +1275,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } f.mContainer = null; f.mView = null; + f.mInLayout = false; } case Fragment.CREATED: if (newState < Fragment.CREATED) { @@ -1340,6 +1335,19 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate moveToState(f, mCurState, 0, 0, false); } + void ensureInflatedFragmentView(Fragment f) { + if (f.mFromLayout && !f.mPerformedCreateView) { + f.mView = f.performCreateView(f.getLayoutInflater( + f.mSavedFragmentState), null, f.mSavedFragmentState); + if (f.mView != null) { + f.mView.setSaveFromParentEnabled(false); + if (f.mHidden) f.mView.setVisibility(View.GONE); + f.onViewCreated(f.mView, f.mSavedFragmentState); + dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false); + } + } + } + /** * Fragments that have been shown or hidden don't have their visibility changed or * animations run during the {@link #showFragment(Fragment)} or {@link #hideFragment(Fragment)} @@ -1445,11 +1453,24 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } - void moveToState(int newState) { + /** + * Changes the state of the fragment manager to {@code newState}. If the fragment manager + * changes state or {@code always} is {@code true}, any fragments within it have their + * states updated as well. + * + * @param newState The new state for the fragment manager + * @param always If {@code true}, all fragments update their state, even + * if {@code newState} matches the current fragment manager's state. + */ + void moveToState(int newState, boolean always) { if (mHost == null && newState != Fragment.INITIALIZING) { throw new IllegalStateException("No activity"); } + if (!always && mCurState == newState) { + return; + } + mCurState = newState; if (mActive != null) { @@ -2024,7 +2045,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate // need to run something now FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, postponeIndex, true); - moveToState(mCurState); + moveToState(mCurState, true); } for (int recordNum = startIndex; recordNum < endIndex; recordNum++) { @@ -2117,7 +2138,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate FragmentTransition.startTransitions(this, records, isRecordPop, 0, 1, true); } if (moveToState) { - moveToState(mCurState); + moveToState(mCurState, true); } else if (mActive != null) { final int numActive = mActive.size(); for (int i = 0; i < numActive; i++) { @@ -2691,40 +2712,40 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate public void dispatchCreate() { mStateSaved = false; - moveToState(Fragment.CREATED); + moveToState(Fragment.CREATED, false); } public void dispatchActivityCreated() { mStateSaved = false; - moveToState(Fragment.ACTIVITY_CREATED); + moveToState(Fragment.ACTIVITY_CREATED, false); } public void dispatchStart() { mStateSaved = false; - moveToState(Fragment.STARTED); + moveToState(Fragment.STARTED, false); } public void dispatchResume() { mStateSaved = false; - moveToState(Fragment.RESUMED); + moveToState(Fragment.RESUMED, false); } public void dispatchPause() { - moveToState(Fragment.STARTED); + moveToState(Fragment.STARTED, false); } public void dispatchStop() { - moveToState(Fragment.STOPPED); + moveToState(Fragment.STOPPED, false); } public void dispatchDestroyView() { - moveToState(Fragment.CREATED); + moveToState(Fragment.CREATED, false); } public void dispatchDestroy() { mDestroyed = true; execPendingActions(); - moveToState(Fragment.INITIALIZING); + moveToState(Fragment.INITIALIZING, false); mHost = null; mContainer = null; mParent = null; @@ -3249,7 +3270,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } // If we haven't finished entering the CREATED state ourselves yet, - // push the inflated child fragment along. + // push the inflated child fragment along. This will ensureInflatedFragmentView + // at the right phase of the lifecycle so that we will have mView populated + // for compliant fragments below. if (mCurState < Fragment.CREATED && fragment.mFromLayout) { moveToState(fragment, Fragment.CREATED, 0, 0, false); } else { diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java index d27dff5e2227..088fd08d97a8 100644 --- a/core/java/android/app/FragmentTransition.java +++ b/core/java/android/app/FragmentTransition.java @@ -24,7 +24,8 @@ import android.util.ArrayMap; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; + +import com.android.internal.view.OneShotPreDrawListener; import java.util.ArrayList; import java.util.Collection; @@ -320,16 +321,9 @@ class FragmentTransition { && exitingFragment.mHidden && exitingFragment.mHiddenChanged) { exitingFragment.setHideReplaced(true); final View fragmentView = exitingFragment.getView(); - final ViewGroup container = exitingFragment.mContainer; - container.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - container.getViewTreeObserver().removeOnPreDrawListener(this); - setViewVisibility(exitingViews, View.INVISIBLE); - return true; - } - }); + OneShotPreDrawListener.add(exitingFragment.mContainer, () -> { + setViewVisibility(exitingViews, View.INVISIBLE); + }); exitTransition.addListener(new Transition.TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { @@ -364,30 +358,22 @@ class FragmentTransition { final Transition enterTransition, final ArrayList<View> enteringViews, final Transition exitTransition, final ArrayList<View> exitingViews) { - sceneRoot.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); - - if (enterTransition != null) { - enterTransition.removeTarget(nonExistentView); - ArrayList<View> views = configureEnteringExitingViews( - enterTransition, inFragment, sharedElementsIn, nonExistentView); - enteringViews.addAll(views); - } - - if (exitingViews != null) { - ArrayList<View> tempExiting = new ArrayList<>(); - tempExiting.add(nonExistentView); - replaceTargets(exitTransition, exitingViews, tempExiting); - exitingViews.clear(); - exitingViews.add(nonExistentView); - } + OneShotPreDrawListener.add(sceneRoot, () -> { + if (enterTransition != null) { + enterTransition.removeTarget(nonExistentView); + ArrayList<View> views = configureEnteringExitingViews( + enterTransition, inFragment, sharedElementsIn, nonExistentView); + enteringViews.addAll(views); + } - return true; - } - }); + if (exitingViews != null) { + ArrayList<View> tempExiting = new ArrayList<>(); + tempExiting.add(nonExistentView); + replaceTargets(exitTransition, exitingViews, tempExiting); + exitingViews.clear(); + exitingViews.add(nonExistentView); + } + }); } /** @@ -541,19 +527,13 @@ class FragmentTransition { epicenterView = null; } - sceneRoot.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); - callSharedElementStartEnd(inFragment, outFragment, inIsPop, - inSharedElements, false); - if (epicenterView != null) { - epicenterView.getBoundsOnScreen(epicenter); - } - return true; - } - }); + OneShotPreDrawListener.add(sceneRoot, () -> { + callSharedElementStartEnd(inFragment, outFragment, inIsPop, + inSharedElements, false); + if (epicenterView != null) { + epicenterView.getBoundsOnScreen(epicenter); + } + }); return sharedElementTransition; } @@ -643,36 +623,30 @@ class FragmentTransition { TransitionSet finalSharedElementTransition = sharedElementTransition; - sceneRoot.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); - ArrayMap<String, View> inSharedElements = captureInSharedElements( - nameOverrides, finalSharedElementTransition, fragments); - - if (inSharedElements != null) { - sharedElementsIn.addAll(inSharedElements.values()); - sharedElementsIn.add(nonExistentView); - } + OneShotPreDrawListener.add(sceneRoot, () -> { + ArrayMap<String, View> inSharedElements = captureInSharedElements( + nameOverrides, finalSharedElementTransition, fragments); - callSharedElementStartEnd(inFragment, outFragment, inIsPop, - inSharedElements, false); - if (finalSharedElementTransition != null) { - finalSharedElementTransition.getTargets().clear(); - finalSharedElementTransition.getTargets().addAll(sharedElementsIn); - replaceTargets(finalSharedElementTransition, sharedElementsOut, - sharedElementsIn); - - final View inEpicenterView = getInEpicenterView(inSharedElements, - fragments, enterTransition, inIsPop); - if (inEpicenterView != null) { - inEpicenterView.getBoundsOnScreen(inEpicenter); - } - } - return true; - } - }); + if (inSharedElements != null) { + sharedElementsIn.addAll(inSharedElements.values()); + sharedElementsIn.add(nonExistentView); + } + + callSharedElementStartEnd(inFragment, outFragment, inIsPop, + inSharedElements, false); + if (finalSharedElementTransition != null) { + finalSharedElementTransition.getTargets().clear(); + finalSharedElementTransition.getTargets().addAll(sharedElementsIn); + replaceTargets(finalSharedElementTransition, sharedElementsOut, + sharedElementsIn); + + final View inEpicenterView = getInEpicenterView(inSharedElements, + fragments, enterTransition, inIsPop); + if (inEpicenterView != null) { + inEpicenterView.getBoundsOnScreen(inEpicenter); + } + } + }); return sharedElementTransition; } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 92d67b7d9f74..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,128 +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 registerUidObserver(in IUidObserver observer, int which, 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; + void keyguardGoingAway(int flags); + void registerUidObserver(in IUidObserver observer, int which, int cutpoint, + 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. * @@ -484,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 setLenientBackgroundCheck(boolean enabled) = 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. * @@ -509,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. @@ -535,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 @@ -546,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 @@ -558,10 +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; + 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); - // 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..6b962b92a66d 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(int timeFormatPreference); + 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. - */ -}
\ No newline at end of file + IVoiceInteractor voiceInteractor); + void handleTrustStorageUpdate(); + void attachAgent(String path); +} diff --git a/core/java/android/app/IEphemeralResolver.aidl b/core/java/android/app/IEphemeralResolver.aidl index ee869eaa7936..260b80c7d634 100644 --- a/core/java/android/app/IEphemeralResolver.aidl +++ b/core/java/android/app/IEphemeralResolver.aidl @@ -21,5 +21,8 @@ import android.os.IRemoteCallback; /** @hide */ oneway interface IEphemeralResolver { void getEphemeralResolveInfoList(IRemoteCallback callback, in int[] digestPrefix, - int prefixMask, int sequence); + int sequence); + + void getEphemeralIntentFilterList(IRemoteCallback callback, String hostName, + int sequence); } diff --git a/core/java/android/app/IInstrumentationWatcher.aidl b/core/java/android/app/IInstrumentationWatcher.aidl index 6c8c4d6e03ef..405a3d80128e 100644 --- a/core/java/android/app/IInstrumentationWatcher.aidl +++ b/core/java/android/app/IInstrumentationWatcher.aidl @@ -21,7 +21,7 @@ import android.content.ComponentName; import android.os.Bundle; /** @hide */ -interface IInstrumentationWatcher +oneway interface IInstrumentationWatcher { void instrumentationStatus(in ComponentName name, int resultCode, in Bundle results); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index ee81c582cc5d..15b99c6e4f7f 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -94,8 +94,8 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); - void applyAdjustmentFromRankerService(in INotificationListener token, in Adjustment adjustment); - void applyAdjustmentsFromRankerService(in INotificationListener token, in List<Adjustment> adjustments); + void applyAdjustmentFromAssistantService(in INotificationListener token, in Adjustment adjustment); + void applyAdjustmentsFromAssistantService(in INotificationListener token, in List<Adjustment> adjustments); ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl index cae54b6c0611..848464cf3823 100644 --- a/core/java/android/app/IUiModeManager.aidl +++ b/core/java/android/app/IUiModeManager.aidl @@ -53,6 +53,16 @@ interface IUiModeManager { int getNightMode(); /** + * Sets whith theme overlays to use within /vendor/overlay. + */ + void setTheme(String theme); + + /** + * Gets whith theme overlays to use within /vendor/overlay. + */ + String getTheme(); + + /** * Tells if UI mode is locked or not. */ boolean isUiModeLocked(); diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl index fa8d0c95e054..64cb9b17f923 100644 --- a/core/java/android/app/IUidObserver.aidl +++ b/core/java/android/app/IUidObserver.aidl @@ -26,7 +26,7 @@ oneway interface IUidObserver { /** * Report that there are no longer any processes running for a uid. */ - void onUidGone(int uid); + void onUidGone(int uid, boolean disabled); /** * Report that a uid is now active (no longer idle). @@ -37,5 +37,5 @@ oneway interface IUidObserver { * Report that a uid is idle -- it has either been running in the background for * a sufficient period of time, or all of its processes have gone away. */ - void onUidIdle(int uid); + void onUidIdle(int uid, boolean disabled); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index f934a9f5d826..cc7981c24027 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1505,7 +1505,7 @@ public class Instrumentation { try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, @@ -1565,7 +1565,7 @@ public class Instrumentation { intents[i].prepareToLeaveProcess(who); resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver()); } - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes, token, options, userId); checkStartActivityResult(result, intents[0]); @@ -1624,7 +1624,7 @@ public class Instrumentation { try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target, requestCode, 0, null, options); @@ -1684,7 +1684,7 @@ public class Instrumentation { try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivityAsUser(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, @@ -1723,7 +1723,7 @@ public class Instrumentation { try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivityAsCaller(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index da99e8005f38..725cc29bd323 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -21,6 +21,7 @@ import android.annotation.RequiresPermission; import android.app.trust.ITrustManager; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Binder; import android.os.RemoteException; @@ -45,6 +46,7 @@ public class KeyguardManager { private IWindowManager mWM; private ITrustManager mTrustManager; private IUserManager mUserManager; + private Context mContext; /** * Intent used to prompt user for device credentials. @@ -87,8 +89,12 @@ public class KeyguardManager { Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL); intent.putExtra(EXTRA_TITLE, title); intent.putExtra(EXTRA_DESCRIPTION, description); - // For security reasons, only allow this to come from system settings. - intent.setPackage("com.android.settings"); + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { + intent.setPackage("com.google.android.apps.wearable.settings"); + } else { + // For security reasons, only allow this to come from system settings. + intent.setPackage("com.android.settings"); + } return intent; } @@ -109,8 +115,12 @@ public class KeyguardManager { intent.putExtra(EXTRA_TITLE, title); intent.putExtra(EXTRA_DESCRIPTION, description); intent.putExtra(Intent.EXTRA_USER_ID, userId); - // For security reasons, only allow this to come from system settings. - intent.setPackage("com.android.settings"); + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { + intent.setPackage("com.google.android.apps.wearable.settings"); + } else { + // For security reasons, only allow this to come from system settings. + intent.setPackage("com.android.settings"); + } return intent; } @@ -193,7 +203,8 @@ public class KeyguardManager { } - KeyguardManager() throws ServiceNotFoundException { + KeyguardManager(Context context) throws ServiceNotFoundException { + mContext = context; mWM = WindowManagerGlobal.getWindowManagerService(); mTrustManager = ITrustManager.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE)); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 7754244cae8e..94d24e49945b 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -339,39 +339,43 @@ public final class LoadedApk { * concatenation of both apps' shared library lists. */ - String instrumentationPackageName = activityThread.mInstrumentationPackageName; - String instrumentationAppDir = activityThread.mInstrumentationAppDir; - String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs; - String instrumentationLibDir = activityThread.mInstrumentationLibDir; - - String instrumentedAppDir = activityThread.mInstrumentedAppDir; - String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs; - String instrumentedLibDir = activityThread.mInstrumentedLibDir; String[] instrumentationLibs = null; - - if (appDir.equals(instrumentationAppDir) - || appDir.equals(instrumentedAppDir)) { - outZipPaths.clear(); - outZipPaths.add(instrumentationAppDir); - if (instrumentationSplitAppDirs != null) { - Collections.addAll(outZipPaths, instrumentationSplitAppDirs); - } - if (!instrumentationAppDir.equals(instrumentedAppDir)) { - outZipPaths.add(instrumentedAppDir); - if (instrumentedSplitAppDirs != null) { - Collections.addAll(outZipPaths, instrumentedSplitAppDirs); + // activityThread will be null when called from the WebView zygote; just assume + // no instrumentation applies in this case. + if (activityThread != null) { + String instrumentationPackageName = activityThread.mInstrumentationPackageName; + String instrumentationAppDir = activityThread.mInstrumentationAppDir; + String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs; + String instrumentationLibDir = activityThread.mInstrumentationLibDir; + + String instrumentedAppDir = activityThread.mInstrumentedAppDir; + String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs; + String instrumentedLibDir = activityThread.mInstrumentedLibDir; + + if (appDir.equals(instrumentationAppDir) + || appDir.equals(instrumentedAppDir)) { + outZipPaths.clear(); + outZipPaths.add(instrumentationAppDir); + if (instrumentationSplitAppDirs != null) { + Collections.addAll(outZipPaths, instrumentationSplitAppDirs); + } + if (!instrumentationAppDir.equals(instrumentedAppDir)) { + outZipPaths.add(instrumentedAppDir); + if (instrumentedSplitAppDirs != null) { + Collections.addAll(outZipPaths, instrumentedSplitAppDirs); + } } - } - if (outLibPaths != null) { - outLibPaths.add(instrumentationLibDir); - if (!instrumentationLibDir.equals(instrumentedLibDir)) { - outLibPaths.add(instrumentedLibDir); + if (outLibPaths != null) { + outLibPaths.add(instrumentationLibDir); + if (!instrumentationLibDir.equals(instrumentedLibDir)) { + outLibPaths.add(instrumentedLibDir); + } } - } - if (!instrumentedAppDir.equals(instrumentationAppDir)) { - instrumentationLibs = getLibrariesFor(instrumentationPackageName); + if (!instrumentedAppDir.equals(instrumentationAppDir)) { + instrumentationLibs = getLibrariesFor(instrumentationPackageName); + } } } @@ -452,7 +456,7 @@ public final class LoadedApk { if (mRegisterPackage) { try { - ActivityManagerNative.getDefault().addPackageDependency(mPackageName); + ActivityManager.getService().addPackageDependency(mPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -891,7 +895,7 @@ public final class LoadedApk { StrictMode.onIntentReceiverLeaked(leak); } try { - ActivityManagerNative.getDefault().unregisterReceiver( + ActivityManager.getService().unregisterReceiver( rd.getIIntentReceiver()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -917,7 +921,7 @@ public final class LoadedApk { StrictMode.onServiceConnectionLeaked(leak); } try { - ActivityManagerNative.getDefault().unbindService( + ActivityManager.getService().unbindService( sd.getIServiceConnection()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1046,7 +1050,7 @@ public final class LoadedApk { // behalf so that the system's broadcast sequence can continue. if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast to unregistered receiver"); - IActivityManager mgr = ActivityManagerNative.getDefault(); + IActivityManager mgr = ActivityManager.getService(); try { if (extras != null) { extras.setAllowFds(false); @@ -1095,7 +1099,7 @@ public final class LoadedApk { + " mOrderedHint=" + ordered); } - final IActivityManager mgr = ActivityManagerNative.getDefault(); + final IActivityManager mgr = ActivityManager.getService(); final Intent intent = mCurIntent; if (intent == null) { Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched); @@ -1209,7 +1213,7 @@ public final class LoadedApk { } if (intent == null || !mActivityThread.post(args)) { if (mRegistered && ordered) { - IActivityManager mgr = ActivityManagerNative.getDefault(); + IActivityManager mgr = ActivityManager.getService(); if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing sync broadcast to " + mReceiver); args.sendFinished(mgr); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index bdb26855c241..1fd082f4683e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2239,7 +2239,7 @@ public class Notification implements Parcelable /** * Returns the id of the channel this notification posts to. */ - public String getNotificationChannel() { + public String getChannel() { return mChannelId; } @@ -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/PendingIntent.java b/core/java/android/app/PendingIntent.java index cfa242be02aa..02d5705f90fc 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -339,7 +339,7 @@ public final class PendingIntent implements Parcelable { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(context); IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, @@ -364,7 +364,7 @@ public final class PendingIntent implements Parcelable { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(context); IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, @@ -481,7 +481,7 @@ public final class PendingIntent implements Parcelable { } try { IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY, packageName, null, null, requestCode, intents, resolvedTypes, flags, options, UserHandle.myUserId()); @@ -507,7 +507,7 @@ public final class PendingIntent implements Parcelable { } try { IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY, packageName, null, null, requestCode, intents, resolvedTypes, flags, options, user.getIdentifier()); @@ -559,7 +559,7 @@ public final class PendingIntent implements Parcelable { try { intent.prepareToLeaveProcess(context); IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_BROADCAST, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, @@ -602,7 +602,7 @@ public final class PendingIntent implements Parcelable { try { intent.prepareToLeaveProcess(context); IIntentSender target = - ActivityManagerNative.getDefault().getIntentSender( + ActivityManager.getService().getIntentSender( ActivityManager.INTENT_SENDER_SERVICE, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, @@ -629,7 +629,7 @@ public final class PendingIntent implements Parcelable { */ public void cancel() { try { - ActivityManagerNative.getDefault().cancelIntentSender(mTarget); + ActivityManager.getService().cancelIntentSender(mTarget); } catch (RemoteException e) { } } @@ -833,7 +833,7 @@ public final class PendingIntent implements Parcelable { String resolvedType = intent != null ? intent.resolveTypeIfNeeded(context.getContentResolver()) : null; - int res = ActivityManagerNative.getDefault().sendIntentSender( + int res = ActivityManager.getService().sendIntentSender( mTarget, code, intent, resolvedType, onFinished != null ? new FinishedDispatcher(this, onFinished, handler) @@ -853,7 +853,7 @@ public final class PendingIntent implements Parcelable { @Deprecated public String getTargetPackage() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getPackageForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -882,7 +882,7 @@ public final class PendingIntent implements Parcelable { @Nullable public String getCreatorPackage() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getPackageForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -910,7 +910,7 @@ public final class PendingIntent implements Parcelable { */ public int getCreatorUid() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getUidForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -941,7 +941,7 @@ public final class PendingIntent implements Parcelable { @Nullable public UserHandle getCreatorUserHandle() { try { - int uid = ActivityManagerNative.getDefault() + int uid = ActivityManager.getService() .getUidForIntentSender(mTarget); return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; } catch (RemoteException e) { @@ -956,7 +956,7 @@ public final class PendingIntent implements Parcelable { */ public boolean isTargetedToPackage() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .isIntentSenderTargetedToPackage(mTarget); } catch (RemoteException e) { // Should never happen. @@ -970,7 +970,7 @@ public final class PendingIntent implements Parcelable { */ public boolean isActivity() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .isIntentSenderAnActivity(mTarget); } catch (RemoteException e) { // Should never happen. @@ -984,7 +984,7 @@ public final class PendingIntent implements Parcelable { */ public Intent getIntent() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getIntentForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -998,7 +998,7 @@ public final class PendingIntent implements Parcelable { */ public String getTag(String prefix) { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getTagForIntentSender(mTarget, prefix); } catch (RemoteException e) { // Should never happen. diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 2d15beb1486f..45831a303bec 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -826,7 +826,8 @@ public class ResourcesManager { for (int i = mResourceImpls.size() - 1; i >= 0; i--) { ResourcesKey key = mResourceImpls.keyAt(i); - ResourcesImpl r = mResourceImpls.valueAt(i).get(); + WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); + ResourcesImpl r = weakImplRef != null ? weakImplRef.get() : null; if (r != null) { if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + r + " config to: " + config); @@ -890,8 +891,9 @@ public class ResourcesManager { final int implCount = mResourceImpls.size(); for (int i = 0; i < implCount; i++) { - final ResourcesImpl impl = mResourceImpls.valueAt(i).get(); final ResourcesKey key = mResourceImpls.keyAt(i); + final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); + final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl != null && key.mResDir.equals(assetPath)) { if (!ArrayUtils.contains(key.mLibDirs, libAsset)) { final int newLibAssetCount = 1 + diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index ee6a3acb6eee..c529e4ba1678 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -946,7 +946,7 @@ public class SearchManager try { Intent intent = new Intent(Intent.ACTION_ASSIST); if (inclContext) { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); Bundle extras = am.getAssistContextExtras(ActivityManager.ASSIST_CONTEXT_BASIC); if (extras != null) { intent.replaceExtras(extras); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index f38c0d817047..3ecc309d75da 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -322,10 +322,10 @@ final class SystemServiceRegistry { }}); registerService(Context.KEYGUARD_SERVICE, KeyguardManager.class, - new StaticServiceFetcher<KeyguardManager>() { + new CachedServiceFetcher<KeyguardManager>() { @Override - public KeyguardManager createService() throws ServiceNotFoundException { - return new KeyguardManager(); + public KeyguardManager createService(ContextImpl ctx) throws ServiceNotFoundException { + return new KeyguardManager(ctx); }}); registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class, diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index b859418867c5..54cc4a096772 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -768,7 +768,7 @@ public final class UiAutomation { throwIfNotConnectedLocked(); } try { - ActivityManagerNative.getDefault().setUserIsMonkey(enable); + ActivityManager.getService().setUserIsMonkey(enable); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while setting run as monkey!", re); } diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index 0046b0e4a8bf..2e2172919dbc 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -241,6 +241,35 @@ public class UiModeManager { } /** + * Sets the vendor theme overlay property, then triggers a reboot. + * @hide + */ + public void setTheme(String theme) { + if (mService != null) { + try { + mService.setTheme(theme); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Gets the vendor theme overlay property. + * @hide + */ + public String getTheme() { + if (mService != null) { + try { + return mService.getTheme(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + + /** * Returns the currently configured night mode. * <p> * May be one of: diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 360087c4dfe1..d89d2bb93f08 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -285,6 +285,27 @@ public class DeviceAdminReceiver extends BroadcastReceiver { = "android.app.action.NETWORK_LOGS_AVAILABLE"; /** + * A {@code long} containing a token of the current batch of network logs, that has to be used + * to retrieve the batch of logs by the device owner. + * + * @see #ACTION_NETWORK_LOGS_AVAILABLE + * @see DevicePolicyManager#retrieveNetworkLogs + * @hide + */ + public static final String EXTRA_NETWORK_LOGS_TOKEN = + "android.app.extra.EXTRA_NETWORK_LOGS_TOKEN"; + + /** + * An {@code int} count representing a total count of network logs inside the current batch of + * network logs. + * + * @see #ACTION_NETWORK_LOGS_AVAILABLE + * @hide + */ + public static final String EXTRA_NETWORK_LOGS_COUNT = + "android.app.extra.EXTRA_NETWORK_LOGS_COUNT"; + + /** * A string containing the SHA-256 hash of the bugreport file. * * @see #ACTION_BUGREPORT_SHARE @@ -336,33 +357,40 @@ public class DeviceAdminReceiver extends BroadcastReceiver { public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; /** @hide */ - public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; + public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = + "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = + "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI = "android.app.extra.CHOOSE_PRIVATE_KEY_URI"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI = + "android.app.extra.CHOOSE_PRIVATE_KEY_URI"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = + "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = + "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE"; /** * Broadcast action: notify device owner that there is a pending system update. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE"; + public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = + "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE"; /** * A long type extra for {@link #onSystemUpdatePending} recording the system time as given by * {@link System#currentTimeMillis()} when the current pending system update is first available. * @hide */ - public static final String EXTRA_SYSTEM_UPDATE_RECEIVED_TIME = "android.app.extra.SYSTEM_UPDATE_RECEIVED_TIME"; + public static final String EXTRA_SYSTEM_UPDATE_RECEIVED_TIME = + "android.app.extra.SYSTEM_UPDATE_RECEIVED_TIME"; /** * Name under which a DevicePolicy component publishes information @@ -644,19 +672,22 @@ public class DeviceAdminReceiver extends BroadcastReceiver { } /** - * Called when a new batch of network logs can be retrieved. This callback method will only ever - * be called when network logging is enabled. The logs can only be retrieved while network + * Called each time a new batch of network logs can be retrieved. This callback method will only + * ever be called when network logging is enabled. The logs can only be retrieved while network * logging is enabled. * * <p>This callback is only applicable to device owners. * * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. + * @param batchToken The token representing the current batch of network logs. + * @param networkLogsCount The total count of events in the current batch of network logs. * @see DevicePolicyManager#retrieveNetworkLogs(ComponentName) * * @hide */ - public void onNetworkLogsAvailable(Context context, Intent intent) { + public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken, + int networkLogsCount) { } /** @@ -714,7 +745,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) { onSecurityLogsAvailable(context, intent); } else if (ACTION_NETWORK_LOGS_AVAILABLE.equals(action)) { - onNetworkLogsAvailable(context, intent); + long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1); + int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0); + onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount); } } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 538e52b97013..0196312580fd 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -20,19 +20,21 @@ import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; -import android.app.admin.NetworkEvent; import android.app.admin.PasswordMetrics; +import android.app.IServiceConnection; import android.app.admin.SecurityLog.SecurityEvent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; @@ -45,10 +47,8 @@ import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; -import android.os.ServiceManager.ServiceNotFoundException; import android.provider.ContactsContract.Directory; import android.provider.Settings; import android.security.Credentials; @@ -6649,8 +6649,6 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param enabled whether network logging should be enabled or not. * @throws {@link SecurityException} if {@code admin} is not a device owner. - * @throws {@link RemoteException} if network logging could not be enabled or disabled due to - * the logging service not being available * @see #retrieveNetworkLogs * * @hide @@ -6683,7 +6681,10 @@ public class DevicePolicyManager { } /** - * Called by device owner to retrieve a new batch of network logging events. + * Called by device owner to retrieve the most recent batch of network logging events. + * A device owner has to provide a batchToken provided as part of + * {@link DeviceAdminReceiver#onNetworkLogsAvailable} callback. If the token doesn't match the + * token of the most recent available batch of logs, {@code null} will be returned. * * <p> {@link NetworkEvent} can be one of {@link DnsEvent} or {@link ConnectEvent}. * @@ -6694,16 +6695,106 @@ public class DevicePolicyManager { * {@link DeviceAdminReceiver#onNetworkLogsAvailable}. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param batchToken A token of the batch to retrieve * @return A new batch of network logs which is a list of {@link NetworkEvent}. Returns - * {@code null} if there's no batch currently awaiting for retrieval or if logging is disabled. + * {@code null} if the batch represented by batchToken is no longer available or if + * logging is disabled. * @throws {@link SecurityException} if {@code admin} is not a device owner. + * @see DeviceAdminReceiver#onNetworkLogsAvailable * * @hide */ - public List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin) { + public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin, + long batchToken) { throwIfParentInstance("retrieveNetworkLogs"); try { - return mService.retrieveNetworkLogs(admin); + return mService.retrieveNetworkLogs(admin, batchToken); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by device owner/ profile owner in managed profile to bind the service with each other. + * The service must be unexported. Note that the {@link Context} used to obtain this + * {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used + * to bind to the {@link android.app.Service}. + * STOPSHIP (b/31952368): Update the javadoc after we policy to control which packages can talk. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param serviceIntent Identifies the service to connect to. The Intent must specify either an + * explicit component name or a package name to match an + * {@link IntentFilter} published by a service. + * @param conn Receives information as the service is started and stopped. This must be a + * valid {@link ServiceConnection} object; it must not be {@code null}. + * @param flags Operation options for the binding operation. See + * {@link Context#bindService(Intent, ServiceConnection, int)}. + * @param targetUser Which user to bind to. + * @return If you have successfully bound to the service, {@code true} is returned; + * {@code false} is returned if the connection is not made and you will not + * receive the service object. + * @see Context#bindService(Intent, ServiceConnection, int) + */ + public boolean bindDeviceAdminServiceAsUser( + @NonNull ComponentName admin, Intent serviceIntent, @NonNull ServiceConnection conn, + @Context.BindServiceFlags int flags, @NonNull UserHandle targetUser) { + throwIfParentInstance("bindDeviceAdminServiceAsUser"); + // Keep this in sync with ContextImpl.bindServiceCommon. + try { + final IServiceConnection sd = mContext.getServiceDispatcher(conn, null, flags); + serviceIntent.prepareToLeaveProcess(mContext); + return mService.bindDeviceAdminServiceAsUser(admin, + mContext.getIApplicationThread(), mContext.getActivityToken(), serviceIntent, + sd, flags, targetUser.getIdentifier()); + } catch (RemoteException re) { + 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 b0aec8cd2571..d14e0d0dfdf0 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -18,6 +18,8 @@ package android.app.admin; import android.app.admin.NetworkEvent; +import android.app.IApplicationThread; +import android.app.IServiceConnection; import android.app.admin.SystemUpdatePolicy; import android.app.admin.PasswordMetrics; import android.content.ComponentName; @@ -318,5 +320,13 @@ interface IDevicePolicyManager { void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled); boolean isNetworkLoggingEnabled(in ComponentName admin); - List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin); + List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin, long batchToken); + + 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/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 6b720c0a22f6..a6f23666cc6d 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -515,6 +515,7 @@ public class AssistStructure implements Parcelable { String mIdPackage; String mIdType; String mIdEntry; + int mAutoFillId = View.NO_ID; int mX; int mY; int mScrollX; @@ -539,6 +540,7 @@ public class AssistStructure implements Parcelable { static final int FLAGS_ACTIVATED = 0x00002000; static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000; + static final int FLAGS_HAS_AUTO_FILL_ID = 0x80000000; static final int FLAGS_HAS_MATRIX = 0x40000000; static final int FLAGS_HAS_ALPHA = 0x20000000; static final int FLAGS_HAS_ELEVATION = 0x10000000; @@ -582,6 +584,9 @@ public class AssistStructure implements Parcelable { } } } + if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) { + mAutoFillId = in.readInt(); + } if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) { mX = in.readInt(); mY = in.readInt(); @@ -637,6 +642,9 @@ public class AssistStructure implements Parcelable { if (mId != View.NO_ID) { flags |= FLAGS_HAS_ID; } + if (mAutoFillId != View.NO_ID) { + flags |= FLAGS_HAS_AUTO_FILL_ID; + } if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0 || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) { flags |= FLAGS_HAS_LARGE_COORDS; @@ -681,6 +689,9 @@ public class AssistStructure implements Parcelable { } } } + if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) { + out.writeInt(mAutoFillId); + } if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) { out.writeInt(mX); out.writeInt(mY); @@ -751,6 +762,16 @@ public class AssistStructure implements Parcelable { } /** + * Returns the id that can be used to auto-fill the view. + * + * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not + * for assist. + */ + public int getAutoFillId() { + return mAutoFillId; + } + + /** * Returns the left edge of this view, in pixels, relative to the left edge of its parent. */ public int getLeft() { @@ -1322,6 +1343,11 @@ public class AssistStructure implements Parcelable { public Rect getTempRect() { return mAssist.mTmpRect; } + + @Override + public void setAutoFillId(int autoFillId) { + mNode.mAutoFillId = autoFillId; + } } /** @hide */ diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index da5aa61f1f21..6cd4e92383b2 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -182,10 +182,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, - * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * end timestamps. Not aggregated over state, uid, metered, or roaming. This means buckets' + * start and end timestamps are going to be the same as the 'startTime' and 'endTime' + * parameters. State, uid, metered, and roaming are going to vary, and tag is going to be the + * same. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -231,7 +231,9 @@ public class NetworkStatsManager { * belonging to calling user. Result is aggregated over state but not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the - * same as the 'uid' parameter and tag the same as 'tag' parameter. + * same as the 'uid' parameter and tag the same as 'tag' parameter. metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be + * {@link NetworkStats.Bucket#ROAMING_ALL}. * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 353c6400ffd7..3de159a6cff2 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.media.AudioManager; +import android.os.Binder; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -572,7 +573,7 @@ public final class BluetoothA2dp implements BluetoothProfile { if (DBG) Log.d(TAG, "Proxy object connected"); try { mServiceLock.writeLock().lock(); - mService = IBluetoothA2dp.Stub.asInterface(service); + mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service)); } finally { mServiceLock.writeLock().unlock(); } diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index 74302f27ec1d..9dfc4b442fa4 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -481,7 +482,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothA2dpSink.Stub.asInterface(service); + mService = IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK, diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index bb344a68e774..b0e27a4ab546 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -604,10 +604,6 @@ public final class BluetoothAdapter { */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { if (!getLeAccess()) return null; - if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) { - Log.e(TAG, "Bluetooth LE advertising not supported"); - return null; - } synchronized(mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); @@ -1357,24 +1353,6 @@ public final class BluetoothAdapter { } /** - * Returns whether peripheral mode is supported. - * - * @hide - */ - public boolean isPeripheralModeSupported() { - if (getState() != STATE_ON) return false; - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.isPeripheralModeSupported(); - } catch (RemoteException e) { - Log.e(TAG, "failed to get peripheral mode capability: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - - /** * Return true if offloaded filters are supported * * @return true if chipset supports on-chip filtering diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java index a395aa470f5b..0261b1b35e2d 100644 --- a/core/java/android/bluetooth/BluetoothAvrcpController.java +++ b/core/java/android/bluetooth/BluetoothAvrcpController.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.ServiceConnection; import android.media.MediaMetadata; import android.media.session.PlaybackState; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -284,7 +285,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothAvrcpController.Stub.asInterface(service); + mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER, diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index f46a3b3c733a..28421ebc4cca 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -20,6 +20,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -1037,7 +1038,7 @@ public final class BluetoothHeadset implements BluetoothProfile { @Override public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothHeadset.Stub.asInterface(service); + mService = IBluetoothHeadset.Stub.asInterface(Binder.allowBlocking(service)); mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_CONNECTED)); } diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 93790feecd11..c7c64c4391c2 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -1122,7 +1123,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @Override public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothHeadsetClient.Stub.asInterface(service); + mService = IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT, diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java index 4949c24372a4..8d77888193b6 100644 --- a/core/java/android/bluetooth/BluetoothHealth.java +++ b/core/java/android/bluetooth/BluetoothHealth.java @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -522,7 +523,7 @@ public final class BluetoothHealth implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothHealth.Stub.asInterface(service); + mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this); diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index 252e3d28a25e..e3288f3c7c88 100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -479,7 +480,7 @@ public final class BluetoothInputDevice implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothInputDevice.Stub.asInterface(service); + mService = IBluetoothInputDevice.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, BluetoothInputDevice.this); diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java index 7f57acf3dc63..2e73051ee610 100644 --- a/core/java/android/bluetooth/BluetoothMap.java +++ b/core/java/android/bluetooth/BluetoothMap.java @@ -371,7 +371,7 @@ public final class BluetoothMap implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) log("Proxy object connected"); - mService = IBluetoothMap.Stub.asInterface(service); + mService = IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this); } diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index 744f9421b239..2a026a91e8e6 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -368,7 +369,7 @@ public final class BluetoothPan implements BluetoothProfile { private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected"); - mPanService = IBluetoothPan.Stub.asInterface(service); + mPanService = IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.PAN, diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java index eab4c6f5130c..9f00e1aaa3a1 100644 --- a/core/java/android/bluetooth/BluetoothPbapClient.java +++ b/core/java/android/bluetooth/BluetoothPbapClient.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.RemoteException; +import android.os.Binder; import android.os.IBinder; import android.util.Log; @@ -288,7 +289,7 @@ public final class BluetoothPbapClient implements BluetoothProfile { if (DBG) { log("Proxy object connected"); } - mService = IBluetoothPbapClient.Stub.asInterface(service); + mService = IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient.this); } diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java index e70c936e253e..89c1bf8f9aa2 100644 --- a/core/java/android/bluetooth/BluetoothSap.java +++ b/core/java/android/bluetooth/BluetoothSap.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.RemoteException; +import android.os.Binder; import android.os.IBinder; import android.os.ServiceManager; import android.util.Log; @@ -393,7 +394,7 @@ public final class BluetoothSap implements BluetoothProfile { private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) log("Proxy object connected"); - mService = IBluetoothSap.Stub.asInterface(service); + mService = IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service)); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.SAP, BluetoothSap.this); } diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index 96a1ae8b9455..7c5458b7704b 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -100,7 +100,6 @@ interface IBluetooth boolean factoryReset(); boolean isMultiAdvertisementSupported(); - boolean isPeripheralModeSupported(); boolean isOffloadedFilteringSupported(); boolean isOffloadedScanBatchingSupported(); boolean isActivityAndEnergyReportingSupported(); diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl index 6ad442b6138d..dde0ac67bbb5 100755 --- a/core/java/android/bluetooth/IBluetoothHeadset.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl @@ -54,7 +54,7 @@ interface IBluetoothHeadset { boolean getAudioRouteAllowed(); boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device); boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device); - void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type); + oneway void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type); void clccResponse(int index, int direction, int status, int mode, boolean mpty, String number, int type); boolean enableWBS(); diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl index 96c59e239151..541583ff5535 100755 --- a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl +++ b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl @@ -24,7 +24,7 @@ import android.os.IBinder; * * {@hide} */ -interface IBluetoothProfileServiceConnection { +oneway interface IBluetoothProfileServiceConnection { void onServiceConnected(in ComponentName comp, in IBinder service); void onServiceDisconnected(in ComponentName comp); } diff --git a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl index feccdce57b98..0da4e8843282 100644 --- a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl @@ -21,7 +21,7 @@ package android.bluetooth; * * {@hide} */ -interface IBluetoothStateChangeCallback +oneway interface IBluetoothStateChangeCallback { void onBluetoothStateChange(boolean on); } diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java index f53ca94a1d5c..9e87230c686e 100644 --- a/core/java/android/bluetooth/OobData.java +++ b/core/java/android/bluetooth/OobData.java @@ -30,10 +30,24 @@ import android.util.Log; * @hide */ public class OobData implements Parcelable { + private byte[] leBluetoothDeviceAddress; private byte[] securityManagerTk; private byte[] leSecureConnectionsConfirmation; private byte[] leSecureConnectionsRandom; + public byte[] getLeBluetoothDeviceAddress() { + return leBluetoothDeviceAddress; + } + + /** + * Sets the LE Bluetooth Device Address value to be used during LE pairing. + * The value shall be 7 bytes. Please see Bluetooth CSSv6, Part A 1.16 for + * a detailed description. + */ + public void setLeBluetoothDeviceAddress(byte[] leBluetoothDeviceAddress) { + this.leBluetoothDeviceAddress = leBluetoothDeviceAddress; + } + public byte[] getSecurityManagerTk() { return securityManagerTk; } @@ -66,6 +80,7 @@ public class OobData implements Parcelable { public OobData() { } private OobData(Parcel in) { + leBluetoothDeviceAddress = in.createByteArray(); securityManagerTk = in.createByteArray(); leSecureConnectionsConfirmation = in.createByteArray(); leSecureConnectionsRandom = in.createByteArray(); @@ -77,6 +92,7 @@ public class OobData implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { + out.writeByteArray(leBluetoothDeviceAddress); out.writeByteArray(securityManagerTk); out.writeByteArray(leSecureConnectionsConfirmation); out.writeByteArray(leSecureConnectionsRandom); diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index 26f2dea9022f..5d276623ce1c 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -111,12 +111,6 @@ public final class BluetoothLeAdvertiser { if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } - if (!mBluetoothAdapter.isMultipleAdvertisementSupported() && - !mBluetoothAdapter.isPeripheralModeSupported()) { - postStartFailure(callback, - AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED); - return; - } boolean isConnectable = settings.isConnectable(); if (totalBytes(advertiseData, isConnectable) > MAX_ADVERTISING_DATA_BYTES || totalBytes(scanResponse, false) > MAX_ADVERTISING_DATA_BYTES) { @@ -236,9 +230,9 @@ public final class BluetoothLeAdvertiser { private final AdvertiseSettings mSettings; private final IBluetoothGatt mBluetoothGatt; - // mAdvertiserId 0: not registered - // -1: advertise stopped or registration timeout - // >0: registered and advertising started + // mAdvertiserId -1: not registered + // -2: advertise stopped or registration timeout + // >=0: registered and advertising started private int mAdvertiserId; private boolean mIsAdvertising = false; @@ -251,12 +245,12 @@ public final class BluetoothLeAdvertiser { mScanResponse = scanResponse; mSettings = settings; mBluetoothGatt = bluetoothGatt; - mAdvertiserId = 0; + mAdvertiserId = -1; } public void startRegisteration() { synchronized (this) { - if (mAdvertiserId == -1) return; + if (mAdvertiserId == -2) return; try { mBluetoothGatt.registerAdvertiser(this); @@ -264,13 +258,13 @@ public final class BluetoothLeAdvertiser { } catch (InterruptedException | RemoteException e) { Log.e(TAG, "Failed to start registeration", e); } - if (mAdvertiserId > 0 && mIsAdvertising) { + if (mAdvertiserId >= 0 && mIsAdvertising) { mLeAdvertisers.put(mAdvertiseCallback, this); - } else if (mAdvertiserId <= 0) { + } else if (mAdvertiserId < 0) { // Registration timeout, reset mClientIf to -1 so no subsequent operations can // proceed. - if (mAdvertiserId == 0) mAdvertiserId = -1; + if (mAdvertiserId == 0) mAdvertiserId = -2; // Post internal error if registration failed. postStartFailure(mAdvertiseCallback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); @@ -278,7 +272,7 @@ public final class BluetoothLeAdvertiser { // Unregister application if it's already registered but advertise failed. try { mBluetoothGatt.unregisterAdvertiser(mAdvertiserId); - mAdvertiserId = -1; + mAdvertiserId = -2; } catch (RemoteException e) { Log.e(TAG, "remote exception when unregistering", e); } @@ -312,7 +306,7 @@ public final class BluetoothLeAdvertiser { synchronized (this) { if (status == BluetoothGatt.GATT_SUCCESS) { try { - if (mAdvertiserId == -1) { + if (mAdvertiserId == -2) { // Registration succeeds after timeout, unregister advertiser. mBluetoothGatt.unregisterAdvertiser(advertiserId); } else { @@ -326,7 +320,7 @@ public final class BluetoothLeAdvertiser { } } // Registration failed. - mAdvertiserId = -1; + mAdvertiserId = -2; notifyAll(); } } @@ -348,7 +342,7 @@ public final class BluetoothLeAdvertiser { // unregister advertiser for stop. try { mBluetoothGatt.unregisterAdvertiser(mAdvertiserId); - mAdvertiserId = -1; + mAdvertiserId = -2; mIsAdvertising = false; mLeAdvertisers.remove(mAdvertiseCallback); } catch (RemoteException e) { diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 10e6fb233249..231dacefa5a1 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -16,7 +16,7 @@ package android.content; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; import android.app.QueuedWork; @@ -366,7 +366,7 @@ public abstract class BroadcastReceiver { */ public final void finish() { if (mType == TYPE_COMPONENT) { - final IActivityManager mgr = ActivityManagerNative.getDefault(); + final IActivityManager mgr = ActivityManager.getService(); if (QueuedWork.hasPendingWork()) { // If this is a broadcast component, we need to make sure any // queued work is complete before telling AM we are done, so @@ -393,7 +393,7 @@ public abstract class BroadcastReceiver { } else if (mOrderedHint && mType != TYPE_UNREGISTERED) { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast to " + mToken); - final IActivityManager mgr = ActivityManagerNative.getDefault(); + final IActivityManager mgr = ActivityManager.getService(); sendFinished(mgr); } } @@ -519,7 +519,7 @@ public abstract class BroadcastReceiver { * Context#startService(Intent)} for more information. */ public IBinder peekService(Context myContext, Intent service) { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); IBinder binder = null; try { service.prepareToLeaveProcess(myContext); diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 1e6424e165c5..f36940958011 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -42,6 +42,7 @@ import android.os.ICancellationSignal; import android.os.OperationCanceledException; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; @@ -463,6 +464,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } } + @Override + public boolean refresh(String callingPkg, Uri uri, Bundle args, + ICancellationSignal cancellationSignal) throws RemoteException { + validateIncomingUri(uri); + uri = getUriWithoutUserId(uri); + if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { + return false; + } + final String original = setCallingPackage(callingPkg); + try { + return ContentProvider.this.refresh(uri, args, + CancellationSignal.fromTransport(cancellationSignal)); + } finally { + setCallingPackage(original); + } + } + private void enforceFilePermission(String callingPkg, Uri uri, String mode, IBinder callerToken) throws FileNotFoundException, SecurityException { if (mode != null && mode.indexOf('w') != -1) { @@ -1093,6 +1111,33 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } /** + * Implement this to support refresh of content identified by {@code uri}. By default, this + * method returns false; providers who wish to implement this should return true to signal the + * client that the provider has tried refreshing with its own implementation. + * <p> + * This allows clients to request an explicit refresh of content identified by {@code uri}. + * <p> + * Client code should only invoke this method when there is a strong indication (such as a user + * initiated pull to refresh gesture) that the content is stale. + * <p> + * Remember to send {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)} + * notifications when content changes. + * + * @param uri The Uri identifying the data to refresh. + * @param args Additional options from the client. The definitions of these are specific to the + * content provider being called. + * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if + * none. For example, if you called refresh on a particular uri, you should call + * {@link CancellationSignal#throwIfCanceled()} to check whether the client has + * canceled the refresh request. + * @return true if the provider actually tried refreshing. + */ + public boolean refresh(Uri uri, @Nullable Bundle args, + @Nullable CancellationSignal cancellationSignal) { + return false; + } + + /** * @hide * Implementation when a caller has performed an insert on the content * provider, but that call has been rejected for the operation given diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index 9221fbb50c96..fd6cddbdde4c 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -147,13 +147,7 @@ public class ContentProviderClient implements AutoCloseable { if (cursor == null) { return null; } - - if ("com.google.android.gms".equals(mPackageName)) { - // They're casting to a concrete subclass, sigh - return cursor; - } else { - return new CursorWrapperInner(cursor); - } + return new CursorWrapperInner(cursor); } catch (DeadObjectException e) { if (!mStable) { mContentResolver.unstableProviderDied(mContentProvider); @@ -234,6 +228,30 @@ public class ContentProviderClient implements AutoCloseable { } } + /** @hide */ + public boolean refresh(Uri url, @Nullable Bundle args, + @Nullable CancellationSignal cancellationSignal) throws RemoteException { + Preconditions.checkNotNull(url, "url"); + + beforeRemote(); + try { + ICancellationSignal remoteCancellationSignal = null; + if (cancellationSignal != null) { + cancellationSignal.throwIfCanceled(); + remoteCancellationSignal = mContentProvider.createCancellationSignal(); + cancellationSignal.setRemote(remoteCancellationSignal); + } + return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal); + } catch (DeadObjectException e) { + if (!mStable) { + mContentResolver.unstableProviderDied(mContentProvider); + } + throw e; + } finally { + afterRemote(); + } + } + /** See {@link ContentProvider#insert ContentProvider.insert} */ public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues) throws RemoteException { diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index 4769bd02a5dc..eadc013db16e 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -355,6 +355,20 @@ abstract public class ContentProviderNative extends Binder implements IContentPr Uri.writeToParcel(reply, out); return true; } + + case REFRESH_TRANSACTION: { + data.enforceInterface(IContentProvider.descriptor); + String callingPkg = data.readString(); + Uri url = Uri.CREATOR.createFromParcel(data); + Bundle args = data.readBundle(); + ICancellationSignal signal = ICancellationSignal.Stub.asInterface( + data.readStrongBinder()); + + boolean out = refresh(callingPkg, url, args, signal); + reply.writeNoException(); + reply.writeInt(out ? 0 : -1); + return true; + } } } catch (Exception e) { DatabaseUtils.writeExceptionToParcel(reply, e); @@ -422,6 +436,7 @@ final class ContentProviderProxy implements IContentProvider if (reply.readInt() != 0) { BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply); + Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null); adaptor.initialize(d); } else { adaptor.close(); @@ -760,5 +775,28 @@ final class ContentProviderProxy implements IContentProvider } } + public boolean refresh(String callingPkg, Uri url, Bundle args, ICancellationSignal signal) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); + + data.writeString(callingPkg); + url.writeToParcel(data, 0); + data.writeBundle(args); + data.writeStrongBinder(signal != null ? signal.asBinder() : null); + + mRemote.transact(IContentProvider.REFRESH_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + int success = reply.readInt(); + return (success == 0); + } finally { + data.recycle(); + reply.recycle(); + } + } + private IBinder mRemote; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index daa1b93889cc..54dcd0a2c81c 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.annotation.UserIdInt; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.content.pm.PackageManager.NameNotFoundException; @@ -194,6 +194,15 @@ public abstract class ContentResolver { public static final String EXTRA_SIZE = "android.content.extra.SIZE"; /** + * An extra boolean describing whether a particular provider supports refresh + * or not. If a provider supports refresh, it should include this key in its + * returned Cursor as part of its query call. + * + * @hide + */ + public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED"; + + /** * This is the Android platform's base MIME type for a content: URI * containing a Cursor of a single item. Applications should use this * as the base type along with their own sub-type of their content: URIs @@ -388,7 +397,7 @@ public abstract class ContentResolver { } try { - String type = ActivityManagerNative.getDefault().getProviderMimeType( + String type = ActivityManager.getService().getProviderMimeType( ContentProvider.getUriWithoutUserId(url), resolveUserId(url)); return type; } catch (RemoteException e) { @@ -664,6 +673,47 @@ public abstract class ContentResolver { } /** + * This allows clients to request an explicit refresh of content identified by {@code uri}. + * <p> + * Client code should only invoke this method when there is a strong indication (such as a user + * initiated pull to refresh gesture) that the content is stale. + * <p> + * + * @param url The Uri identifying the data to refresh. + * @param args Additional options from the client. The definitions of these are specific to the + * content provider being called. + * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if + * none. For example, if you called refresh on a particular uri, you should call + * {@link CancellationSignal#throwIfCanceled()} to check whether the client has + * canceled the refresh request. + * @return true if the provider actually tried refreshing. + */ + public final boolean refresh(@NonNull Uri url, @Nullable Bundle args, + @Nullable CancellationSignal cancellationSignal) { + Preconditions.checkNotNull(url, "url"); + IContentProvider provider = acquireProvider(url); + if (provider == null) { + return false; + } + + try { + ICancellationSignal remoteCancellationSignal = null; + if (cancellationSignal != null) { + cancellationSignal.throwIfCanceled(); + remoteCancellationSignal = provider.createCancellationSignal(); + cancellationSignal.setRemote(remoteCancellationSignal); + } + return provider.refresh(mPackageName, url, args, remoteCancellationSignal); + } catch (RemoteException e) { + // Arbitrary and not worth documenting, as Activity + // Manager will kill this process shortly anyway. + return false; + } finally { + releaseProvider(provider); + } + } + + /** * Open a stream on to the content associated with a content URI. If there * is no data associated with the URI, FileNotFoundException is thrown. * @@ -1792,7 +1842,7 @@ public abstract class ContentResolver { @Intent.AccessUriMode int modeFlags) { Preconditions.checkNotNull(uri, "uri"); try { - ActivityManagerNative.getDefault().takePersistableUriPermission( + ActivityManager.getService().takePersistableUriPermission( ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } @@ -1810,7 +1860,7 @@ public abstract class ContentResolver { @Intent.AccessUriMode int modeFlags) { Preconditions.checkNotNull(uri, "uri"); try { - ActivityManagerNative.getDefault().releasePersistableUriPermission( + ActivityManager.getService().releasePersistableUriPermission( ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } @@ -1828,7 +1878,7 @@ public abstract class ContentResolver { */ public @NonNull List<UriPermission> getPersistedUriPermissions() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getPersistedUriPermissions(mPackageName, true).getList(); } catch (RemoteException e) { throw new RuntimeException("Activity manager has died", e); @@ -1844,7 +1894,7 @@ public abstract class ContentResolver { */ public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getPersistedUriPermissions(mPackageName, false).getList(); } catch (RemoteException e) { throw new RuntimeException("Activity manager has died", e); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 322cc7b9becc..5fa427514ebe 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -32,6 +32,10 @@ import android.annotation.StyleableRes; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UserIdInt; +import android.app.IApplicationThread; +import android.app.IServiceConnection; +import android.app.LoadedApk; +import android.app.admin.DevicePolicyManager; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -2333,7 +2337,7 @@ public abstract class Context { * matches <var>filter</var>, in the main application thread. * * <p>The system may broadcast Intents that are "sticky" -- these stay - * around after the broadcast as finished, to be sent to any later + * around after the broadcast has finished, to be sent to any later * registrations. If your IntentFilter matches one of these sticky * Intents, that Intent will be returned by this function * <strong>and</strong> sent to your <var>receiver</var> as if it had just @@ -3338,6 +3342,14 @@ public abstract class Context { public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction"; /** + * Official published name of the (internal) auto-fill service. + * + * @hide + * @see #getSystemService + */ + public static final String AUTO_FILL_MANAGER_SERVICE = "autofill"; + + /** * Use with {@link #getSystemService} to access the * {@link com.android.server.voiceinteraction.SoundTriggerService}. * @@ -4355,4 +4367,27 @@ public abstract class Context { public boolean isCredentialEncryptedStorage() { return isCredentialProtectedStorage(); } + + /** + * @hide + */ + public IBinder getActivityToken() { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** + * @hide + */ + @Nullable + public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler, + int flags) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** + * @hide + */ + public IApplicationThread getIApplicationThread() { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } } diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index edc8d824e5c4..75336559088b 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -16,7 +16,10 @@ package android.content; +import android.annotation.Nullable; import android.annotation.SystemApi; +import android.app.IApplicationThread; +import android.app.IServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -857,4 +860,29 @@ public class ContextWrapper extends Context { public boolean isCredentialProtectedStorage() { return mBase.isCredentialProtectedStorage(); } + + /** + * @hide + */ + @Override + public IBinder getActivityToken() { + return mBase.getActivityToken(); + } + + /** + * @hide + */ + @Override + public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler, + int flags) { + return mBase.getServiceDispatcher(conn, handler, flags); + } + + /** + * @hide + */ + @Override + public IApplicationThread getIApplicationThread() { + return mBase.getIApplicationThread(); + } } diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 4afe38b62851..ee8a22fb7f0f 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -65,6 +65,9 @@ public interface IContentProvider extends IInterface { public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException; public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException; + public boolean refresh(String callingPkg, Uri url, @Nullable Bundle args, + ICancellationSignal cancellationSignal) throws RemoteException; + // Data interchange. public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException; public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType, @@ -88,4 +91,5 @@ public interface IContentProvider extends IInterface { static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23; static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24; static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25; + static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26; } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 4eecd48df646..50589fea233b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1713,6 +1713,16 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME"; /** + * Intent extra: An app split name. + * <p> + * Type: String + * </p> + * @hide + */ + @SystemApi + public static final String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME"; + + /** * Intent extra: An extra for specifying whether a result is needed. * <p> * Type: boolean @@ -3120,10 +3130,11 @@ public class Intent implements Parcelable, Cloneable { * URIs that can be opened with * {@link ContentResolver#openFileDescriptor(Uri, String)}. * <p> - * Callers can set a document URI through {@link #setData(Uri)} to indicate - * the initial location of documents navigator. System will do its best to - * launch the navigator in the specified document if it's a folder, or the - * folder that contains the specified document if not. + * Callers can set a document URI through + * {@link DocumentsContract#EXTRA_INITIAL_URI} to indicate the initial + * location of documents navigator. System will do its best to launch the + * navigator in the specified document if it's a folder, or the folder that + * contains the specified document if not. * <p> * Output: The URI of the item that was picked, returned in * {@link #getData()}. This must be a {@code content://} URI so that any @@ -3161,10 +3172,11 @@ public class Intent implements Parcelable, Cloneable { * URIs that can be opened with * {@link ContentResolver#openFileDescriptor(Uri, String)}. * <p> - * Callers can set a document URI through {@link #setData(Uri)} to indicate - * the initial location of documents navigator. System will do its best to - * launch the navigator in the specified document if it's a folder, or the - * folder that contains the specified document if not. + * Callers can set a document URI through + * {@link DocumentsContract#EXTRA_INITIAL_URI} to indicate the initial + * location of documents navigator. System will do its best to launch the + * navigator in the specified document if it's a folder, or the folder that + * contains the specified document if not. * <p> * Output: The URI of the item that was created. This must be a * {@code content://} URI so that any receiver can access it. @@ -3188,10 +3200,11 @@ public class Intent implements Parcelable, Cloneable { * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} * with the returned URI. * <p> - * Callers can set a document URI through {@link #setData(Uri)} to indicate - * the initial location of documents navigator. System will do its best to - * initiate the navigator in the specified document if it's a folder, or - * the folder that contains the specified document if not. + * Callers can set a document URI through + * {@link DocumentsContract#EXTRA_INITIAL_URI} to indicate the initial + * location of documents navigator. System will do its best to launch the + * navigator in the specified document if it's a folder, or the folder that + * contains the specified document if not. * <p> * Output: The URI representing the selected directory tree. * @@ -3822,6 +3835,18 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_EPHEMERAL_FAILURE = "android.intent.extra.EPHEMERAL_FAILURE"; /** + * The host name that triggered an ephemeral resolution. + * @hide + */ + public static final String EXTRA_EPHEMERAL_HOSTNAME = "android.intent.extra.EPHEMERAL_HOSTNAME"; + + /** + * An opaque token to track ephemeral resolution. + * @hide + */ + public static final String EXTRA_EPHEMERAL_TOKEN = "android.intent.extra.EPHEMERAL_TOKEN"; + + /** * A Bundle forming a mapping of potential target package names to different extras Bundles * to add to the default intent extras in {@link #EXTRA_INTENT} when used with * {@link #ACTION_CHOOSER}. Each key should be a package name. The package need not @@ -4161,13 +4186,21 @@ public class Intent implements Parcelable, Cloneable { = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; /** - * Optional boolean extra for {@link #ACTION_TIME_CHANGED} that indicates the - * user has set their time format preferences to the 24 hour format. + * Optional int extra for {@link #ACTION_TIME_CHANGED} that indicates the + * user has set their time format preference. See {@link #EXTRA_TIME_PREF_VALUE_USE_12_HOUR}, + * {@link #EXTRA_TIME_PREF_VALUE_USE_24_HOUR} and + * {@link #EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT}. The value must not be negative. * * @hide for internal use only. */ public static final String EXTRA_TIME_PREF_24_HOUR_FORMAT = "android.intent.extra.TIME_PREF_24_HOUR_FORMAT"; + /** @hide */ + public static final int EXTRA_TIME_PREF_VALUE_USE_12_HOUR = 0; + /** @hide */ + public static final int EXTRA_TIME_PREF_VALUE_USE_24_HOUR = 1; + /** @hide */ + public static final int EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT = 2; /** {@hide} */ public static final String EXTRA_REASON = "android.intent.extra.REASON"; diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index 32ca6c2d4bac..4adb5b7ab557 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -16,7 +16,7 @@ package android.content; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.os.Bundle; import android.os.RemoteException; import android.os.Handler; @@ -187,7 +187,7 @@ public class IntentSender implements Parcelable { String resolvedType = intent != null ? intent.resolveTypeIfNeeded(context.getContentResolver()) : null; - int res = ActivityManagerNative.getDefault().sendIntentSender(mTarget, + int res = ActivityManager.getService().sendIntentSender(mTarget, code, intent, resolvedType, onFinished != null ? new FinishedDispatcher(this, onFinished, handler) @@ -207,7 +207,7 @@ public class IntentSender implements Parcelable { @Deprecated public String getTargetPackage() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getPackageForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -226,7 +226,7 @@ public class IntentSender implements Parcelable { */ public String getCreatorPackage() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getPackageForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -245,7 +245,7 @@ public class IntentSender implements Parcelable { */ public int getCreatorUid() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getUidForIntentSender(mTarget); } catch (RemoteException e) { // Should never happen. @@ -266,7 +266,7 @@ public class IntentSender implements Parcelable { */ public UserHandle getCreatorUserHandle() { try { - int uid = ActivityManagerNative.getDefault() + int uid = ActivityManager.getService() .getUidForIntentSender(mTarget); return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; } catch (RemoteException e) { diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 74ec8e4c32de..9b99bbfe8880 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -489,6 +489,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6; /** + * Value for {@link #flags}: {@code true} if the application is blocked via restrictions + * and for most purposes is considered as not installed. + * {@hide} + */ + public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 7; + + /** * When set, at least one component inside this application is direct boot * aware. * @@ -496,12 +503,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE = 1 << 8; - /** - * Value for {@link #flags}: {@code true} if the application is blocked via restrictions - * and for most purposes is considered as not installed. - * {@hide} - */ - public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 9; /** * When set, signals that the application is required for the system user and should not be @@ -509,7 +510,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * * @hide */ - public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 10; + public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 9; /** * When set, the application explicitly requested that its activities by resizeable by default. @@ -517,7 +518,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * * @hide */ - public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET = 1 << 11; + public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET = 1 << 10; /** * The application isn't requesting explicitly requesting for its activities to be resizeable or @@ -531,7 +532,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * * @hide */ - public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION = 1 << 12; + public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION = 1 << 11; /** * Value for {@link #privateFlags}: {@code true} means the OS should go ahead and @@ -539,7 +540,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * foreground-equivalent run state. Defaults to {@code false} if unspecified. * @hide */ - public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 13; + public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12; /** * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants. @@ -1219,5 +1220,5 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** {@hide} */ public String[] getSplitCodePaths() { return splitSourceDirs; } /** {@hide} */ public String getResourcePath() { return scanPublicSourceDir; } /** {@hide} */ public String getBaseResourcePath() { return publicSourceDir; } - /** {@hide} */ public String[] getSplitResourcePaths() { return splitSourceDirs; } + /** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; } } diff --git a/core/java/android/content/pm/EphemeralIntentFilter.java b/core/java/android/content/pm/EphemeralIntentFilter.java new file mode 100644 index 000000000000..0674e7c21631 --- /dev/null +++ b/core/java/android/content/pm/EphemeralIntentFilter.java @@ -0,0 +1,96 @@ +/* + * 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.content.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.IntentFilter; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Information about an ephemeral application intent filter. + * @hide + */ +@SystemApi +public final class EphemeralIntentFilter implements Parcelable { + private final String mSplitName; + /** The filters used to match domain */ + private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>(); + + public EphemeralIntentFilter(@Nullable String splitName, @NonNull List<IntentFilter> filters) { + if (filters == null || filters.size() == 0) { + throw new IllegalArgumentException(); + } + mSplitName = splitName; + mFilters.addAll(filters); + } + + EphemeralIntentFilter(Parcel in) { + mSplitName = in.readString(); + in.readList(mFilters, null /*loader*/); + } + + public String getSplitName() { + return mSplitName; + } + + public List<IntentFilter> getFilters() { + return mFilters; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(mSplitName); + out.writeList(mFilters); + } + + public static final Parcelable.Creator<EphemeralIntentFilter> CREATOR + = new Parcelable.Creator<EphemeralIntentFilter>() { + public EphemeralIntentFilter createFromParcel(Parcel in) { + return new EphemeralIntentFilter(in); + } + + public EphemeralIntentFilter[] newArray(int size) { + return new EphemeralIntentFilter[size]; + } + }; + + /** @hide */ + public static final class EphemeralResolveIntentInfo extends IntentFilter { + private final EphemeralIntentFilter mResolveInfo; + + public EphemeralResolveIntentInfo(@NonNull IntentFilter orig, + @NonNull EphemeralIntentFilter resolveInfo) { + super(orig); + this.mResolveInfo = resolveInfo; + } + + public EphemeralIntentFilter getEphemeralResolveInfo() { + return mResolveInfo; + } + } +} diff --git a/core/java/android/content/pm/EphemeralRequest.java b/core/java/android/content/pm/EphemeralRequest.java new file mode 100644 index 000000000000..7f2b3ee1245b --- /dev/null +++ b/core/java/android/content/pm/EphemeralRequest.java @@ -0,0 +1,48 @@ +/* + * 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.content.pm; + +import android.content.Intent; + +/** + * Information needed to make an ephemeral application resolution request. + * @hide + */ +public final class EphemeralRequest { + /** Response from the first phase of ephemeral application resolution */ + public final EphemeralResponse responseObj; + /** The original intent that triggered ephemeral application resolution */ + public final Intent origIntent; + /** Resolved type of the intent */ + public final String resolvedType; + /** The intent that would launch if there were no ephemeral applications */ + public final Intent launchIntent; + /** The name of the package requesting the ephemeral application */ + public final String callingPackage; + /** ID of the user requesting the ephemeral application */ + public final int userId; + + public EphemeralRequest(EphemeralResponse responseObj, Intent origIntent, + String resolvedType, Intent launchIntent, String callingPackage, int userId) { + this.responseObj = responseObj; + this.origIntent = origIntent; + this.resolvedType = resolvedType; + this.launchIntent = launchIntent; + this.callingPackage = callingPackage; + this.userId = userId; + } +}
\ No newline at end of file diff --git a/core/java/android/content/pm/EphemeralResolveInfo.java b/core/java/android/content/pm/EphemeralResolveInfo.java index fc3b95850d21..f6200886cd71 100644 --- a/core/java/android/content/pm/EphemeralResolveInfo.java +++ b/core/java/android/content/pm/EphemeralResolveInfo.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.IntentFilter; import android.net.Uri; @@ -41,27 +42,54 @@ public final class EphemeralResolveInfo implements Parcelable { private final EphemeralDigest mDigest; private final String mPackageName; /** The filters used to match domain */ - private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>(); + private final List<EphemeralIntentFilter> mFilters; + /** Filters only for legacy clients */ + @Deprecated + private List<IntentFilter> mLegacyFilters; + @Deprecated public EphemeralResolveInfo(@NonNull Uri uri, @NonNull String packageName, @NonNull List<IntentFilter> filters) { - // validate arguments - if (uri == null - || packageName == null - || filters == null - || filters.size() == 0) { + if (uri == null || packageName == null || filters == null || filters.isEmpty()) { throw new IllegalArgumentException(); } + mDigest = new EphemeralDigest(uri.getHost()); + mPackageName = packageName; + mFilters = new ArrayList<EphemeralIntentFilter>(); + mFilters.add(new EphemeralIntentFilter(packageName, filters)); + mLegacyFilters = new ArrayList<IntentFilter>(filters.size()); + mLegacyFilters.addAll(filters); + } - mDigest = new EphemeralDigest(uri, 0xFFFFFFFF, -1); - mFilters.addAll(filters); + public EphemeralResolveInfo(@NonNull EphemeralDigest digest, @Nullable String packageName, + @Nullable List<EphemeralIntentFilter> filters) { + // validate arguments + if ((packageName == null && (filters != null && filters.size() != 0)) + || (packageName != null && (filters == null || filters.size() == 0))) { + throw new IllegalArgumentException(); + } + mDigest = digest; + if (filters != null) { + mFilters = new ArrayList<EphemeralIntentFilter>(filters.size()); + mFilters.addAll(filters); + } else { + mFilters = null; + } mPackageName = packageName; } + public EphemeralResolveInfo(@NonNull String hostName, @Nullable String packageName, + @Nullable List<EphemeralIntentFilter> filters) { + this(new EphemeralDigest(hostName), packageName, filters); + } + EphemeralResolveInfo(Parcel in) { mDigest = in.readParcelable(null /*loader*/); mPackageName = in.readString(); + mFilters = new ArrayList<EphemeralIntentFilter>(); in.readList(mFilters, null /*loader*/); + mLegacyFilters = new ArrayList<IntentFilter>(); + in.readList(mLegacyFilters, null /*loader*/); } public byte[] getDigestBytes() { @@ -76,7 +104,12 @@ public final class EphemeralResolveInfo implements Parcelable { return mPackageName; } + @Deprecated public List<IntentFilter> getFilters() { + return mLegacyFilters; + } + + public List<EphemeralIntentFilter> getIntentFilters() { return mFilters; } @@ -90,6 +123,7 @@ public final class EphemeralResolveInfo implements Parcelable { out.writeParcelable(mDigest, flags); out.writeString(mPackageName); out.writeList(mFilters); + out.writeList(mLegacyFilters); } public static final Parcelable.Creator<EphemeralResolveInfo> CREATOR @@ -103,21 +137,6 @@ public final class EphemeralResolveInfo implements Parcelable { } }; - /** @hide */ - public static final class EphemeralResolveIntentInfo extends IntentFilter { - private final EphemeralResolveInfo mResolveInfo; - - public EphemeralResolveIntentInfo(@NonNull IntentFilter orig, - @NonNull EphemeralResolveInfo resolveInfo) { - super(orig); - this.mResolveInfo = resolveInfo; - } - - public EphemeralResolveInfo getEphemeralResolveInfo() { - return mResolveInfo; - } - } - /** * Helper class to generate and store each of the digests and prefixes * sent to the Ephemeral Resolver. @@ -129,17 +148,25 @@ public final class EphemeralResolveInfo implements Parcelable { * * @hide */ + @SystemApi public static final class EphemeralDigest implements Parcelable { + private static final int DIGEST_MASK = 0xfffff000; + private static final int DIGEST_PREFIX_COUNT = 5; /** Full digest of the domain hashes */ private final byte[][] mDigestBytes; /** The first 4 bytes of the domain hashes */ private final int[] mDigestPrefix; - public EphemeralDigest(@NonNull Uri uri, int digestMask, int maxDigests) { - if (uri == null) { + public EphemeralDigest(@NonNull String hostName) { + this(hostName, -1 /*maxDigests*/); + } + + /** @hide */ + public EphemeralDigest(@NonNull String hostName, int maxDigests) { + if (hostName == null) { throw new IllegalArgumentException(); } - mDigestBytes = generateDigest(uri, maxDigests); + mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests); mDigestPrefix = new int[mDigestBytes.length]; for (int i = 0; i < mDigestBytes.length; i++) { mDigestPrefix[i] = @@ -147,31 +174,32 @@ public final class EphemeralResolveInfo implements Parcelable { | (mDigestBytes[i][1] & 0xFF) << 16 | (mDigestBytes[i][2] & 0xFF) << 8 | (mDigestBytes[i][3] & 0xFF) << 0) - & digestMask; + & DIGEST_MASK; } } - private static byte[][] generateDigest(Uri uri, int maxDigests) { + private static byte[][] generateDigest(String hostName, int maxDigests) { ArrayList<byte[]> digests = new ArrayList<>(); try { - final String host = uri.getHost().toLowerCase(Locale.ENGLISH); final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM); if (maxDigests <= 0) { - final byte[] hostBytes = host.getBytes(); + final byte[] hostBytes = hostName.getBytes(); digests.add(digest.digest(hostBytes)); } else { - int prevDot = host.lastIndexOf('.'); - prevDot = host.lastIndexOf('.', prevDot - 1); + int prevDot = hostName.lastIndexOf('.'); + prevDot = hostName.lastIndexOf('.', prevDot - 1); // shortcut for short URLs if (prevDot < 0) { - digests.add(digest.digest(host.getBytes())); + digests.add(digest.digest(hostName.getBytes())); } else { - byte[] hostBytes = host.substring(prevDot + 1, host.length()).getBytes(); + byte[] hostBytes = + hostName.substring(prevDot + 1, hostName.length()).getBytes(); digests.add(digest.digest(hostBytes)); int digestCount = 1; while (prevDot >= 0 && digestCount < maxDigests) { - prevDot = host.lastIndexOf('.', prevDot - 1); - hostBytes = host.substring(prevDot + 1, host.length()).getBytes(); + prevDot = hostName.lastIndexOf('.', prevDot - 1); + hostBytes = + hostName.substring(prevDot + 1, hostName.length()).getBytes(); digests.add(digest.digest(hostBytes)); digestCount++; } diff --git a/core/java/android/content/pm/EphemeralResponse.java b/core/java/android/content/pm/EphemeralResponse.java new file mode 100644 index 000000000000..6e569f7d4667 --- /dev/null +++ b/core/java/android/content/pm/EphemeralResponse.java @@ -0,0 +1,51 @@ +/* + * 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.content.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.IntentFilter; + +/** + * Ephemeral application resolution response. + * @hide + */ +public final class EphemeralResponse extends IntentFilter { + /** Resolved information returned from the external ephemeral resolver */ + public final EphemeralResolveInfo resolveInfo; + /** The resolved package. Copied from {@link #resolveInfo}. */ + public final String packageName; + /** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */ + public final String splitName; + /** Whether or not ephemeral resolution needs the second phase */ + public final boolean needsPhase2; + /** Opaque token to track the ephemeral application resolution */ + public final String token; + + public EphemeralResponse(@NonNull EphemeralResolveInfo resolveInfo, + @NonNull IntentFilter orig, + @Nullable String splitName, + @NonNull String token, + boolean needsPhase2) { + super(orig); + this.resolveInfo = resolveInfo; + this.packageName = resolveInfo.getPackageName(); + this.splitName = splitName; + this.token = token; + this.needsPhase2 = needsPhase2; + } +}
\ No newline at end of file diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 11f0eb626964..d753a6eaa1c6 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -492,7 +492,7 @@ interface IPackageManager { /** * Update status of external media on the package manager to scan and * install packages installed on the external media. Like say the - * MountService uses this to call into the package manager to update + * StorageManagerService uses this to call into the package manager to update * status of sdcard. */ void updateExternalMediaStatus(boolean mounted, boolean reportStatus); 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/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 1f013ae02a87..ad0a6b25c4f1 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -17,6 +17,7 @@ package android.content.pm; import android.content.ComponentName; +import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.util.SparseArray; @@ -162,6 +163,12 @@ public abstract class PackageManagerInternal { public abstract boolean isPackageDataProtected(int userId, String packageName); /** + * Returns {@code true} if a given package is installed as ephemeral. Otherwise, returns + * {@code false}. + */ + public abstract boolean isPackageEphemeral(int userId, String packageName); + + /** * Gets whether the package was ever launched. * @param packageName The package name. * @param userId The user for which to check. @@ -202,4 +209,16 @@ public abstract class PackageManagerInternal { */ public abstract String getNameForUid(int uid); + /** + * Request to perform the second phase of ephemeral resolution. + * @param responseObj The response of the first phase of ephemeral resolution + * @param origIntent The original intent that triggered ephemeral resolution + * @param resolvedType The resolved type of the intent + * @param launchIntent The intent that would launch if there was no ephemeral application + * @param callingPackage The name of the package requesting the ephemeral application + * @param userId The ID of the user that triggered ephemeral resolution + */ + public abstract void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj, + Intent origIntent, String resolvedType, Intent launchIntent, String callingPackage, + int userId); } diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index b5df4d75a238..f8b4570be6cc 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -65,7 +65,7 @@ public class ResolveInfo implements Parcelable { * only be set in specific circumstances. * @hide */ - public EphemeralResolveInfo ephemeralResolveInfo; + public EphemeralResponse ephemeralResponse; /** * The IntentFilter that was matched for this ResolveInfo. diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index a93870ece823..f7c4d592b3a9 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -193,7 +193,11 @@ import java.util.List; * The following list includes descriptions for the different attributes within a static shortcut: * <dl> * <dt>{@code android:shortcutId}</dt> - * <dd>Mandatory shortcut ID</dd> + * <dd>Mandatory shortcut ID. + * <p> + * This must be a string literal. + * A resource string, such as <code>@string/foo</code>, cannot be used. + * </dd> * * <dt>{@code android:enabled}</dt> * <dd>Default is {@code true}. Can be set to {@code false} in order @@ -206,15 +210,24 @@ import java.util.List; * * <dt>{@code android:shortcutShortLabel}</dt> * <dd>Mandatory shortcut short label. - * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</dd> + * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}. + * <p> + * This must be a resource string, such as <code>@string/shortcut_label</code>. + * </dd> * * <dt>{@code android:shortcutLongLabel}</dt> * <dd>Shortcut long label. - * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</dd> + * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}. + * <p> + * This must be a resource string, such as <code>@string/shortcut_long_label</code>. + * </dd> * * <dt>{@code android:shortcutDisabledMessage}</dt> * <dd>When {@code android:enabled} is set to - * {@code false}, this attribute is used to display a custom disabled message.</dd> + * {@code false}, this attribute is used to display a custom disabled message. + * <p> + * This must be a resource string, such as <code>@string/shortcut_disabled_message</code>. + * </dd> * * <dt>{@code intent}</dt> * <dd>Intent to launch when the user selects the shortcut. diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 8233ad2f6f63..c46fe29d07a5 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -553,6 +553,7 @@ public class ResourcesImpl { if (!mPreloading && useCache) { final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme); if (cachedDrawable != null) { + cachedDrawable.setChangingConfigurations(value.changingConfigurations); return cachedDrawable; } } @@ -588,9 +589,11 @@ public class ResourcesImpl { // If we were able to obtain a drawable, store it in the appropriate // cache: preload, not themed, null theme, or theme-specific. Don't // pollute the cache with drawables loaded from a foreign density. - if (dr != null && useCache) { + if (dr != null) { dr.setChangingConfigurations(value.changingConfigurations); - cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); + if (useCache) { + cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); + } } return dr; diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index f17fd55bd22a..cdf7013deb26 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -19,7 +19,7 @@ package android.hardware.fingerprint; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.Context; import android.os.Binder; import android.os.CancellationSignal; @@ -892,7 +892,7 @@ public class FingerprintManager { private int getCurrentUserId() { try { - return ActivityManagerNative.getDefault().getCurrentUser().id; + return ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl index d2c3d7555e70..3fe645c59a30 100644 --- a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl +++ b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl @@ -25,7 +25,7 @@ import android.hardware.location.IActivityRecognitionHardware; * * @hide */ -interface IActivityRecognitionHardwareClient { +oneway interface IActivityRecognitionHardwareClient { /** * Hardware Activity-Recognition availability event. * diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl index c99cb0c6126f..a7dd0351010d 100644 --- a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl +++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl @@ -24,7 +24,7 @@ import android.location.Location; * * @hide */ -interface IFusedLocationHardwareSink { +oneway interface IFusedLocationHardwareSink { /** * Event generated when a batch of location information is available. * @@ -50,4 +50,4 @@ interface IFusedLocationHardwareSink { * changes (location is successful/unsuccessful). */ void onStatusChanged(int status) = 3; -}
\ No newline at end of file +} 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/net/RoughtimeClient.java b/core/java/android/net/RoughtimeClient.java new file mode 100644 index 000000000000..cf4d8a2d3f5a --- /dev/null +++ b/core/java/android/net/RoughtimeClient.java @@ -0,0 +1,499 @@ +/* + * 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; + +import android.os.SystemClock; +import android.util.Log; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; + +/** + * {@hide} + * + * Simple Roughtime client class for retrieving network time. + */ +public class RoughtimeClient +{ + private static final String TAG = "RoughtimeClient"; + private static final boolean ENABLE_DEBUG = true; + + private static final int ROUGHTIME_PORT = 5333; + + private static final int MIN_REQUEST_SIZE = 1024; + + private static final int NONCE_SIZE = 64; + + private static final int MAX_DATAGRAM_SIZE = 65507; + + private final SecureRandom random = new SecureRandom(); + + /** + * Tag values. Exposed for use in tests only. + */ + protected static enum Tag { + /** + * Nonce used to initiate a transaction. + */ + NONC(0x434e4f4e), + + /** + * Signed portion of a response. + **/ + SREP(0x50455253), + + /** + * Pad data. Always the largest tag lexicographically. + */ + PAD(0xff444150), + + /** + * A signature for a neighboring SREP. + */ + SIG(0x474953), + + /** + * Server certificate. + */ + CERT(0x54524543), + + /** + * Position in the Merkle tree. + */ + INDX(0x58444e49), + + /** + * Upward path in the Merkle tree. + */ + PATH(0x48544150), + + /** + * Midpoint of the time interval in the response. + */ + MIDP(0x5044494d), + + /** + * Radius of the time interval in the response. + */ + RADI(0x49444152), + + /** + * Root of the Merkle tree. + */ + ROOT(0x544f4f52), + + /** + * Delegation from the long term key to an online key. + */ + DELE(0x454c4544), + + /** + * Online public key. + */ + PUBK(0x4b425550), + + /** + * Earliest midpoint time the given PUBK can authenticate. + */ + MINT(0x544e494d), + + /** + * Latest midpoint time the given PUBK can authenticate. + */ + MAXT(0x5458414d); + + private final int value; + + Tag(int value) { + this.value = value; + } + + private int value() { + return value; + } + } + + /** + * A result retrieved from a roughtime server. + */ + private static class Result { + public long midpoint; + public int radius; + public long collectionTime; + } + + /** + * A Roughtime protocol message. Functionally a serializable map from Tags + * to byte arrays. + */ + protected static class Message { + private HashMap<Integer,byte[]> items = new HashMap<Integer,byte[]>(); + public int padSize = 0; + + public Message() {} + + /** + * Set the given data for the given tag. + */ + public void put(Tag tag, byte[] data) { + put(tag.value(), data); + } + + private void put(int tag, byte[] data) { + items.put(tag, data); + } + + /** + * Get the data associated with the given tag. + */ + public byte[] get(Tag tag) { + return items.get(tag.value()); + } + + /** + * Get the data associated with the given tag and decode it as a 64-bit + * integer. + */ + public long getLong(Tag tag) { + ByteBuffer b = ByteBuffer.wrap(get(tag)); + return b.getLong(); + } + + /** + * Get the data associated with the given tag and decode it as a 32-bit + * integer. + */ + public int getInt(Tag tag) { + ByteBuffer b = ByteBuffer.wrap(get(tag)); + return b.getInt(); + } + + /** + * Encode the given long value as a 64-bit little-endian value and + * associate it with the given tag. + */ + public void putLong(Tag tag, long l) { + ByteBuffer b = ByteBuffer.allocate(8); + b.putLong(l); + put(tag, b.array()); + } + + /** + * Encode the given int value as a 32-bit little-endian value and + * associate it with the given tag. + */ + public void putInt(Tag tag, int l) { + ByteBuffer b = ByteBuffer.allocate(4); + b.putInt(l); + put(tag, b.array()); + } + + /** + * Get a packed representation of this message suitable for the wire. + */ + public byte[] serialize() { + if (items.size() == 0) { + if (padSize > 4) + return new byte[padSize]; + else + return new byte[4]; + } + + int size = 0; + + ArrayList<Integer> offsets = new ArrayList<Integer>(); + ArrayList<Integer> tagList = new ArrayList<Integer>(items.keySet()); + Collections.sort(tagList); + + boolean first = true; + for (int tag : tagList) { + if (! first) { + offsets.add(size); + } + + first = false; + size += items.get(tag).length; + } + + ByteBuffer dataBuf = ByteBuffer.allocate(size); + dataBuf.order(ByteOrder.LITTLE_ENDIAN); + + int valueDataSize = size; + size += 4 + offsets.size() * 4 + tagList.size() * 4; + + int tagCount = items.size(); + + if (size < padSize) { + offsets.add(valueDataSize); + tagList.add(Tag.PAD.value()); + + if (size + 8 > padSize) { + size = size + 8; + } else { + size = padSize; + } + + tagCount += 1; + } + + ByteBuffer buf = ByteBuffer.allocate(size); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putInt(tagCount); + + for (int offset : offsets) { + buf.putInt(offset); + } + + for (int tag : tagList) { + buf.putInt(tag); + + if (tag != Tag.PAD.value()) { + dataBuf.put(items.get(tag)); + } + } + + buf.put(dataBuf.array()); + + return buf.array(); + } + + /** + * Given a byte stream from the wire, unpack it into a Message object. + */ + public static Message deserialize(byte[] data) { + ByteBuffer buf = ByteBuffer.wrap(data); + buf.order(ByteOrder.LITTLE_ENDIAN); + + Message msg = new Message(); + + int count = buf.getInt(); + + if (count == 0) { + return msg; + } + + ArrayList<Integer> offsets = new ArrayList<Integer>(); + offsets.add(0); + + for (int i = 1; i < count; i++) { + offsets.add(buf.getInt()); + } + + ArrayList<Integer> tags = new ArrayList<Integer>(); + for (int i = 0; i < count; i++) { + int tag = buf.getInt(); + tags.add(tag); + } + + offsets.add(buf.remaining()); + + for (int i = 0; i < count; i++) { + int tag = tags.get(i); + int start = offsets.get(i); + int end = offsets.get(i+1); + byte[] content = new byte[end - start]; + + buf.get(content); + if (tag != Tag.PAD.value()) { + msg.put(tag, content); + } + } + + return msg; + } + + /** + * Send this message over the given socket to the given address and port. + */ + public void send(DatagramSocket socket, InetAddress address, int port) + throws IOException { + byte[] buffer = serialize(); + DatagramPacket message = new DatagramPacket(buffer, buffer.length, + address, port); + socket.send(message); + } + + /** + * Receive a Message object from the given socket. + */ + public static Message receive(DatagramSocket socket) + throws IOException { + byte[] buffer = new byte[MAX_DATAGRAM_SIZE]; + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + + socket.receive(packet); + + return deserialize(Arrays.copyOf(buffer, packet.getLength())); + } + } + + private MessageDigest messageDigest = null; + + private final ArrayList<Result> results = new ArrayList<Result>(); + private long lastRequest = 0; + + private Message createRequestMessage() { + byte[] nonce = new byte[NONCE_SIZE]; + random.nextBytes(nonce); // TODO: Chain nonces + + assert nonce.length == NONCE_SIZE : + "Nonce must be " + NONCE_SIZE + " bytes."; + + Message msg = new Message(); + + msg.put(Tag.NONC, nonce); + msg.padSize = MIN_REQUEST_SIZE; + + return msg; + } + + /** + * Contact the Roughtime server at the given address and port and collect a + * result time to add to our collection. + * + * @param host host name of the server. + * @param timeout network timeout in milliseconds. + * @return true if the transaction was successful. + */ + public boolean requestTime(String host, int timeout) { + InetAddress address = null; + try { + address = InetAddress.getByName(host); + } catch (Exception e) { + if (ENABLE_DEBUG) { + Log.d(TAG, "request time failed", e); + } + + return false; + } + return requestTime(address, ROUGHTIME_PORT, timeout); + } + + /** + * Contact the Roughtime server at the given address and port and collect a + * result time to add to our collection. + * + * @param address address for the server. + * @param port port to talk to the server on. + * @param timeout network timeout in milliseconds. + * @return true if the transaction was successful. + */ + public boolean requestTime(InetAddress address, int port, int timeout) { + + final long rightNow = SystemClock.elapsedRealtime(); + + if ((rightNow - lastRequest) > timeout) { + results.clear(); + } + + lastRequest = rightNow; + + DatagramSocket socket = null; + try { + if (messageDigest == null) { + messageDigest = MessageDigest.getInstance("SHA-512"); + } + + socket = new DatagramSocket(); + socket.setSoTimeout(timeout); + final long startTime = SystemClock.elapsedRealtime(); + Message request = createRequestMessage(); + request.send(socket, address, port); + final long endTime = SystemClock.elapsedRealtime(); + Message response = Message.receive(socket); + byte[] signedData = response.get(Tag.SREP); + Message signedResponse = Message.deserialize(signedData); + + final Result result = new Result(); + result.midpoint = signedResponse.getLong(Tag.MIDP); + result.radius = signedResponse.getInt(Tag.RADI); + result.collectionTime = (startTime + endTime) / 2; + + final byte[] root = signedResponse.get(Tag.ROOT); + final byte[] path = response.get(Tag.PATH); + final byte[] nonce = request.get(Tag.NONC); + final int index = response.getInt(Tag.INDX); + + if (! verifyNonce(root, path, nonce, index)) { + Log.w(TAG, "failed to authenticate roughtime response."); + return false; + } + + results.add(result); + } catch (Exception e) { + if (ENABLE_DEBUG) { + Log.d(TAG, "request time failed", e); + } + + return false; + } finally { + if (socket != null) { + socket.close(); + } + } + + return true; + } + + /** + * Verify that a reply message corresponds to the nonce sent in the request. + * + * @param root Root of the Merkle tree used to sign the nonce. Received in + * the ROOT tag of the reply. + * @param path Sibling hashes along the path to the root of the Merkle tree. + * Received in the PATH tag of the reply. + * @param nonce The nonce we sent in the request. + * @param index Bitfield indicating whether chunks of the path are left or + * right children. + * @return true if the verification is successful. + */ + private boolean verifyNonce(byte[] root, byte[] path, byte[] nonce, + int index) { + messageDigest.update(new byte[]{ 0 }); + byte[] hash = messageDigest.digest(nonce); + int pos = 0; + byte[] one = new byte[]{ 1 }; + + while (pos < path.length) { + messageDigest.update(one); + + if ((index&1) != 0) { + messageDigest.update(path, pos, 64); + hash = messageDigest.digest(hash); + } else { + messageDigest.update(hash); + messageDigest.update(path, pos, 64); + hash = messageDigest.digest(); + } + + pos += 64; + index >>>= 1; + } + + return Arrays.equals(root, hash); + } +} diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 1ac9fca51b77..e7436be273a3 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -108,6 +108,26 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; + /** @hide */ + public static final int TAG_SYSTEM_DHCP = 0xFFFFFF05; + /** @hide */ + public static final int TAG_SYSTEM_NTP = 0xFFFFFF06; + /** @hide */ + public static final int TAG_SYSTEM_PROBE = 0xFFFFFF07; + /** @hide */ + public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF08; + /** @hide */ + public static final int TAG_SYSTEM_GPS = 0xFFFFFF09; + /** @hide */ + public static final int TAG_SYSTEM_PAC = 0xFFFFFF0A; + + /** + * Sockets that are strictly local on device; never hits network. + * + * @hide + */ + public static final int TAG_SYSTEM_LOCAL = 0xFFFFFFAA; + private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java index a5b4eb5aff86..e0a026ed678d 100644 --- a/core/java/android/net/metrics/IpManagerEvent.java +++ b/core/java/android/net/metrics/IpManagerEvent.java @@ -38,9 +38,15 @@ public final class IpManagerEvent implements Parcelable { public static final int PROVISIONING_OK = 1; public static final int PROVISIONING_FAIL = 2; public static final int COMPLETE_LIFECYCLE = 3; + /** @hide */ public static final int ERROR_STARTING_IPV4 = 4; + /** @hide */ public static final int ERROR_STARTING_IPV6 = 5; + /** @hide */ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; /** {@hide} */ - @IntDef(value = {PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE}) + @IntDef(value = { + PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE, + ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR, + }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} @@ -95,6 +101,7 @@ public final class IpManagerEvent implements Parcelable { final static class Decoder { static final SparseArray<String> constants = MessageUtils.findMessageNames( - new Class[]{IpManagerEvent.class}, new String[]{"PROVISIONING_", "COMPLETE_"}); + new Class[]{IpManagerEvent.class}, + new String[]{"PROVISIONING_", "COMPLETE_", "ERROR_"}); } } diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 252385faf089..263750aa9946 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -16,6 +16,7 @@ package android.os; +import android.hardware.health.V1_0.Constants; import com.android.internal.app.IBatteryStats; /** @@ -118,20 +119,20 @@ public class BatteryManager { public static final String EXTRA_CHARGE_COUNTER = "charge_counter"; // values for "status" field in the ACTION_BATTERY_CHANGED Intent - public static final int BATTERY_STATUS_UNKNOWN = 1; - public static final int BATTERY_STATUS_CHARGING = 2; - public static final int BATTERY_STATUS_DISCHARGING = 3; - public static final int BATTERY_STATUS_NOT_CHARGING = 4; - public static final int BATTERY_STATUS_FULL = 5; + public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN; + public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING; + public static final int BATTERY_STATUS_DISCHARGING = Constants.BATTERY_STATUS_DISCHARGING; + public static final int BATTERY_STATUS_NOT_CHARGING = Constants.BATTERY_STATUS_NOT_CHARGING; + public static final int BATTERY_STATUS_FULL = Constants.BATTERY_STATUS_FULL; // values for "health" field in the ACTION_BATTERY_CHANGED Intent - public static final int BATTERY_HEALTH_UNKNOWN = 1; - public static final int BATTERY_HEALTH_GOOD = 2; - public static final int BATTERY_HEALTH_OVERHEAT = 3; - public static final int BATTERY_HEALTH_DEAD = 4; - public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5; - public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; - public static final int BATTERY_HEALTH_COLD = 7; + public static final int BATTERY_HEALTH_UNKNOWN = Constants.BATTERY_HEALTH_UNKNOWN; + public static final int BATTERY_HEALTH_GOOD = Constants.BATTERY_HEALTH_GOOD; + public static final int BATTERY_HEALTH_OVERHEAT = Constants.BATTERY_HEALTH_OVERHEAT; + public static final int BATTERY_HEALTH_DEAD = Constants.BATTERY_HEALTH_DEAD; + public static final int BATTERY_HEALTH_OVER_VOLTAGE = Constants.BATTERY_HEALTH_OVER_VOLTAGE; + public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = Constants.BATTERY_HEALTH_UNSPECIFIED_FAILURE; + public static final int BATTERY_HEALTH_COLD = Constants.BATTERY_HEALTH_COLD; // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent. // These must be powers of 2. diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 7b7533b16410..01369791fd38 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -75,36 +75,35 @@ public class Binder implements IBinder { /** * Control whether dump() calls are allowed. */ - private static String sDumpDisabled = null; + private static volatile String sDumpDisabled = null; /** * Global transaction tracker instance for this process. */ - private static TransactionTracker sTransactionTracker = null; + private static volatile TransactionTracker sTransactionTracker = null; // Transaction tracking code. /** * Flag indicating whether we should be tracing transact calls. - * */ - private static boolean sTracingEnabled = false; + private static volatile boolean sTracingEnabled = false; /** * Enable Binder IPC tracing. * * @hide */ - public static void enableTracing() { + public static void enableTracing() { sTracingEnabled = true; - }; + } /** * Disable Binder IPC tracing. * * @hide */ - public static void disableTracing() { + public static void disableTracing() { sTracingEnabled = false; } @@ -128,6 +127,59 @@ public class Binder implements IBinder { return sTransactionTracker; } + /** {@hide} */ + static volatile boolean sWarnOnBlocking = false; + + /** + * Warn if any blocking binder transactions are made out from this process. + * This is typically only useful for the system process, to prevent it from + * blocking on calls to external untrusted code. Instead, all outgoing calls + * that require a result must be sent as {@link IBinder#FLAG_ONEWAY} calls + * which deliver results through a callback interface. + * + * @hide + */ + public static void setWarnOnBlocking(boolean warnOnBlocking) { + sWarnOnBlocking = warnOnBlocking; + } + + /** + * Allow blocking calls on the given interface, overriding the requested + * value of {@link #setWarnOnBlocking(boolean)}. + * <p> + * This should only be rarely called when you are <em>absolutely sure</em> + * the remote interface is a built-in system component that can never be + * upgraded. In particular, this <em>must never</em> be called for + * interfaces hosted by package that could be upgraded or replaced, + * otherwise you risk system instability if that remote interface wedges. + * + * @hide + */ + public static IBinder allowBlocking(IBinder binder) { + try { + if (binder instanceof BinderProxy) { + ((BinderProxy) binder).mWarnOnBlocking = false; + } else if (binder != null + && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) { + Log.w(TAG, "Unable to allow blocking on interface " + binder); + } + } catch (RemoteException ignored) { + } + return binder; + } + + /** + * Inherit the current {@link #allowBlocking(IBinder)} value from one given + * interface to another. + * + * @hide + */ + public static void copyAllowBlocking(IBinder fromBinder, IBinder toBinder) { + if (fromBinder instanceof BinderProxy && toBinder instanceof BinderProxy) { + ((BinderProxy) toBinder).mWarnOnBlocking = ((BinderProxy) fromBinder).mWarnOnBlocking; + } + } + /* mObject is used by native code, do not remove or rename */ private long mObject; private IInterface mOwner; @@ -322,9 +374,7 @@ public class Binder implements IBinder { * re-enabled. */ public static void setDumpDisabled(String msg) { - synchronized (Binder.class) { - sDumpDisabled = msg; - } + sDumpDisabled = msg; } /** @@ -400,10 +450,7 @@ public class Binder implements IBinder { } void doDump(FileDescriptor fd, PrintWriter pw, String[] args) { - final String disabled; - synchronized (Binder.class) { - disabled = sDumpDisabled; - } + final String disabled = sDumpDisabled; if (disabled == null) { try { dump(fd, pw, args); @@ -612,6 +659,9 @@ public class Binder implements IBinder { } final class BinderProxy implements IBinder { + // Assume the process-wide default value when created + volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking; + public native boolean pingBinder(); public native boolean isBinderAlive(); @@ -621,6 +671,15 @@ final class BinderProxy implements IBinder { public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); + + if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) { + // For now, avoid spamming the log by disabling after we've logged + // about this interface at least once + mWarnOnBlocking = false; + Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY", + new Throwable()); + } + final boolean tracingEnabled = Binder.isTracingEnabled(); if (tracingEnabled) { final Throwable tr = new Throwable(); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index e5832c8064d3..0d6d36961750 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -924,16 +924,4 @@ public class Build { return -1; } } - - /** - * Check if the device is running on the Android O release or newer. - * - * @return {@code true} if O APIs are available for use - * - * @hide - */ - public static boolean isAtLeastO() { - return !"REL".equals(VERSION.CODENAME) - && "O".compareTo(VERSION.CODENAME) <= 0; - } } diff --git a/core/java/android/os/CountDownTimer.java b/core/java/android/os/CountDownTimer.java index 58acbcf5684b..c7bf0fd6ba49 100644 --- a/core/java/android/os/CountDownTimer.java +++ b/core/java/android/os/CountDownTimer.java @@ -125,19 +125,28 @@ public abstract class CountDownTimer { if (millisLeft <= 0) { onFinish(); - } else if (millisLeft < mCountdownInterval) { - // no tick, just delay until done - sendMessageDelayed(obtainMessage(MSG), millisLeft); } else { long lastTickStart = SystemClock.elapsedRealtime(); onTick(millisLeft); // take into account user's onTick taking time to execute - long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime(); - - // special case: user's onTick took more than interval to - // complete, skip to next interval - while (delay < 0) delay += mCountdownInterval; + long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart; + long delay; + + if (millisLeft < mCountdownInterval) { + // just delay until done + delay = millisLeft - lastTickDuration; + + // special case: user's onTick took more than interval to + // complete, trigger onFinish without delay + if (delay < 0) delay = 0; + } else { + delay = mCountdownInterval - lastTickDuration; + + // special case: user's onTick took more than interval to + // complete, skip to next interval + while (delay < 0) delay += mCountdownInterval; + } sendMessageDelayed(obtainMessage(MSG), delay); } diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java index 0e7da63a2215..481b2dc096d5 100644 --- a/core/java/android/os/HwBinder.java +++ b/core/java/android/os/HwBinder.java @@ -16,6 +16,7 @@ package android.os; +import java.util.ArrayList; import libcore.util.NativeAllocationRegistry; /** @hide */ @@ -39,10 +40,12 @@ public abstract class HwBinder implements IHwBinder { int code, HwParcel request, HwParcel reply, int flags); public native final void registerService( - String serviceName, int versionMajor, int versionMinor); + ArrayList<String> interfaceChain, + String serviceName); public static native final IHwBinder getService( - String serviceName, int versionMajor, int versionMinor); + String iface, + String serviceName); // Returns address of the "freeFunction". private static native final long native_init(); diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 3546e17698b9..819afb4806b0 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -77,6 +77,7 @@ public class RemoteCallbackList<E extends IInterface> { public boolean register(E callback) { return register(callback, null); } + /** * Add a new callback to the list. This callback will remain in the list * until a corresponding call to {@link #unregister} or its hosting process @@ -326,4 +327,27 @@ public class RemoteCallbackList<E extends IInterface> { return mCallbacks.size(); } } + + /** + * Return the cookies associated with a currently registered callback. Note that this is + * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used + * interchangeably with it. This method returns the current cookied registered at the given + * index, not the current broadcast state. This means that it is not itself thread-safe: + * any call to {@link #register} or {@link #unregister} will change these indices, so you + * must do your own thread safety between these to protect from such changes. + * + * @param index Index of which registration cookie to return from 0 to + * {@link #getRegisteredCallbackCount()}. + * + * @return Returns whatever cookie object is associated with this index, or null if + * {@link #kill()} has been called. + */ + public Object getRegisteredCallbackCookie(int index) { + synchronized (mCallbacks) { + if (mKilled) { + return null; + } + return mCallbacks.valueAt(index).mCookie; + } + } } diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java index 640105ce8f98..e11494d5cd41 100644 --- a/core/java/android/os/ServiceManager.java +++ b/core/java/android/os/ServiceManager.java @@ -36,7 +36,8 @@ public final class ServiceManager { } // Find the service manager - sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); + sServiceManager = ServiceManagerNative + .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); return sServiceManager; } @@ -52,7 +53,7 @@ public final class ServiceManager { if (service != null) { return service; } else { - return getIServiceManager().getService(name); + return Binder.allowBlocking(getIServiceManager().getService(name)); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); @@ -117,7 +118,7 @@ public final class ServiceManager { if (service != null) { return service; } else { - return getIServiceManager().checkService(name); + return Binder.allowBlocking(getIServiceManager().checkService(name)); } } catch (RemoteException e) { Log.e(TAG, "error in checkService", e); diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index e9a39360c7bf..ef79b666741a 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -17,7 +17,6 @@ package android.os; import android.animation.ValueAnimator; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.ApplicationErrorReport; import android.app.IActivityManager; @@ -1606,7 +1605,7 @@ public final class StrictMode { public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); try { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (am == null) { Log.d(TAG, "No activity manager; failed to Dropbox violation."); } else { @@ -1943,7 +1942,7 @@ public final class StrictMode { // We restore the current policy below, in the finally block. setThreadPolicyMask(0); - ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( + ActivityManager.getService().handleApplicationStrictModeViolation( RuntimeInit.getApplicationObject(), violationMaskSubset, info); diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index d31036c532c7..6a751e808d4b 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -77,6 +77,7 @@ public class SystemProperties { private static native boolean native_get_boolean(String key, boolean def); private static native void native_set(String key, String def); private static native void native_add_change_callback(); + private static native void native_report_sysprop_change(); /** * Get the value for the given key. @@ -195,4 +196,11 @@ public class SystemProperties { } } } + + /* + * Notifies listeners that a system property has changed + */ + public static void reportSyspropChanged() { + native_report_sysprop_change(); + } } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 15dd282880e4..50eb7cf5e647 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -26,7 +26,6 @@ import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; @@ -983,7 +982,7 @@ public class UserManager { public boolean isUserRunning(int userId) { // TODO Switch to using UMS internal isUserRunning try { - return ActivityManagerNative.getDefault().isUserRunning(userId, 0); + return ActivityManager.getService().isUserRunning(userId, 0); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -999,7 +998,7 @@ public class UserManager { public boolean isUserRunningOrStopping(UserHandle user) { try { // TODO: reconcile stopped vs stopping? - return ActivityManagerNative.getDefault().isUserRunning( + return ActivityManager.getService().isUserRunning( user.getIdentifier(), ActivityManager.FLAG_OR_STOPPED); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); @@ -1016,7 +1015,7 @@ public class UserManager { @Deprecated public boolean isUserRunningAndLocked(UserHandle user) { try { - return ActivityManagerNative.getDefault().isUserRunning( + return ActivityManager.getService().isUserRunning( user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); @@ -1033,7 +1032,7 @@ public class UserManager { @Deprecated public boolean isUserRunningAndUnlocked(UserHandle user) { try { - return ActivityManagerNative.getDefault().isUserRunning( + return ActivityManager.getService().isUserRunning( user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); @@ -1080,7 +1079,7 @@ public class UserManager { /** {@hide} */ public boolean isUserUnlocked(@UserIdInt int userId) { try { - return ActivityManagerNative.getDefault().isUserRunning(userId, + return ActivityManager.getService().isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); diff --git a/core/java/android/os/storage/IObbActionListener.aidl b/core/java/android/os/storage/IObbActionListener.aidl index 61ba4d56e6a3..a86ba598c6d3 100644 --- a/core/java/android/os/storage/IObbActionListener.aidl +++ b/core/java/android/os/storage/IObbActionListener.aidl @@ -17,7 +17,7 @@ package android.os.storage; /** - * Callback class for receiving events from MountService about Opaque Binary + * Callback class for receiving events from StorageManagerService about Opaque Binary * Blobs (OBBs). * * Don't change the existing transaction Ids as they could be used in the native code. diff --git a/core/java/android/os/storage/IMountServiceListener.aidl b/core/java/android/os/storage/IStorageEventListener.aidl index 0e20cd326585..4ba1dbed1652 100644 --- a/core/java/android/os/storage/IMountServiceListener.aidl +++ b/core/java/android/os/storage/IStorageEventListener.aidl @@ -21,15 +21,15 @@ import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; /** - * Callback class for receiving events from MountService. + * Callback class for receiving events from StorageManagerService. * * 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. * - * @hide - Applications should use IStorageEventListener for storage event - * callbacks. + * @hide - Applications should use {@link android.os.storage.StorageEventListener} class for + * storage event callbacks. */ -oneway interface IMountServiceListener { +oneway interface IStorageEventListener { /** * Detection state of USB Mass Storage has changed * diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IStorageManager.aidl index 390df99c73a9..98cbce6c175d 100644 --- a/core/java/android/os/storage/IMountService.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -19,8 +19,8 @@ package android.os.storage; import android.content.pm.IPackageMoveObserver; import android.os.ParcelFileDescriptor; import android.os.storage.DiskInfo; -import android.os.storage.IMountServiceListener; -import android.os.storage.IMountShutdownObserver; +import android.os.storage.IStorageEventListener; +import android.os.storage.IStorageShutdownObserver; import android.os.storage.IObbActionListener; import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; @@ -34,15 +34,15 @@ import android.os.storage.VolumeRecord; * @hide - Applications should use android.os.storage.StorageManager to access * storage functions. */ -interface IMountService { +interface IStorageManager { /** - * Registers an IMountServiceListener for receiving async notifications. + * Registers an IStorageEventListener for receiving async notifications. */ - void registerListener(IMountServiceListener listener) = 0; + void registerListener(IStorageEventListener listener) = 0; /** - * Unregisters an IMountServiceListener + * Unregisters an IStorageEventListener */ - void unregisterListener(IMountServiceListener listener) = 1; + void unregisterListener(IStorageEventListener listener) = 1; /** * Returns true if a USB mass storage host is connected */ @@ -58,7 +58,7 @@ interface IMountService { boolean isUsbMassStorageEnabled() = 4; /** * Mount external storage at given mount point. Returns an int consistent - * with MountServiceResultCode + * with StorageResultCode */ int mountVolume(in String mountPoint) = 5; /** @@ -74,7 +74,7 @@ interface IMountService { void unmountVolume(in String mountPoint, boolean force, boolean removeEncryption) = 6; /** * Format external storage given a mount point. Returns an int consistent - * with MountServiceResultCode + * with StorageResultCode */ int formatVolume(in String mountPoint) = 7; /** @@ -87,30 +87,30 @@ interface IMountService { String getVolumeState(in String mountPoint) = 9; /* * Creates a secure container with the specified parameters. Returns an int - * consistent with MountServiceResultCode + * consistent with StorageResultCode */ int createSecureContainer(in String id, int sizeMb, in String fstype, in String key, int ownerUid, boolean external) = 10; /* * Finalize a container which has just been created and populated. After * finalization, the container is immutable. Returns an int consistent with - * MountServiceResultCode + * StorageResultCode */ int finalizeSecureContainer(in String id) = 11; /* * Destroy a secure container, and free up all resources associated with it. * NOTE: Ensure all references are released prior to deleting. Returns an - * int consistent with MountServiceResultCode + * int consistent with StorageResultCode */ int destroySecureContainer(in String id, boolean force) = 12; /* * Mount a secure container with the specified key and owner UID. Returns an - * int consistent with MountServiceResultCode + * int consistent with StorageResultCode */ int mountSecureContainer(in String id, in String key, int ownerUid, boolean readOnly) = 13; /* * Unount a secure container. Returns an int consistent with - * MountServiceResultCode + * StorageResultCode */ int unmountSecureContainer(in String id, boolean force) = 14; /* @@ -119,7 +119,7 @@ interface IMountService { boolean isSecureContainerMounted(in String id) = 15; /* * Rename an unmounted secure container. Returns an int consistent with - * MountServiceResultCode + * StorageResultCode */ int renameSecureContainer(in String oldId, in String newId) = 16; /* @@ -131,19 +131,19 @@ interface IMountService { */ String[] getSecureContainerList() = 18; /** - * Shuts down the MountService and gracefully unmounts all external media. + * Shuts down the StorageManagerService and gracefully unmounts all external media. * Invokes call back once the shutdown is complete. */ - void shutdown(IMountShutdownObserver observer) = 19; + void shutdown(IStorageShutdownObserver observer) = 19; /** - * Call into MountService by PackageManager to notify that its done + * Call into StorageManagerService by PackageManager to notify that its done * processing the media status update request. */ void finishMediaUpdate() = 20; /** * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and * only allows the calling process's UID access to the contents. - * MountService will call back to the supplied IObbActionListener to inform + * StorageManagerService will call back to the supplied IObbActionListener to inform * it of the terminal state of the call. */ void mountObb(in String rawPath, in String canonicalPath, in String key, @@ -151,7 +151,7 @@ interface IMountService { /** * Unmounts an Opaque Binary Blob (OBB). When the force flag is specified, * any program using it will be forcibly killed to unmount the image. - * MountService will call back to the supplied IObbActionListener to inform + * StorageManagerService will call back to the supplied IObbActionListener to inform * it of the terminal state of the call. */ void unmountObb(in String rawPath, boolean force, IObbActionListener token, int nonce) = 22; @@ -209,7 +209,7 @@ interface IMountService { int verifyEncryptionPassword(in String password) = 32; /* * Fix permissions in a container which has just been created and populated. - * Returns an int consistent with MountServiceResultCode + * Returns an int consistent with StorageResultCode */ int fixPermissionsSecureContainer(in String id, int gid, in String filename) = 33; /** diff --git a/core/java/android/os/storage/IMountShutdownObserver.aidl b/core/java/android/os/storage/IStorageShutdownObserver.aidl index f3e1654c4128..b28421791c64 100644 --- a/core/java/android/os/storage/IMountShutdownObserver.aidl +++ b/core/java/android/os/storage/IStorageShutdownObserver.aidl @@ -24,9 +24,9 @@ package android.os.storage; * * @hide - For internal consumption only. */ -interface IMountShutdownObserver { +interface IStorageShutdownObserver { /** - * This method is called when the shutdown of MountService completed. + * This method is called when the shutdown of StorageManagerService completed. * * @param statusCode indicates success or failure of the shutdown. */ diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 1942fdee23dc..0472e02d8886 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -152,7 +152,7 @@ public class StorageManager { /** @hide Underlying data is corrupt */ public static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4; - private static volatile IMountService sMountService = null; + private static volatile IStorageManager sStorageManager = null; // TODO: the location of the primary storage block varies from device to device, so we need to // try the most likely candidates - a long-term solution would be a device-specific vold @@ -166,13 +166,13 @@ public class StorageManager { private final Context mContext; private final ContentResolver mResolver; - private final IMountService mMountService; + private final IStorageManager mStorageManager; private final Looper mLooper; private final AtomicInteger mNextNonce = new AtomicInteger(0); private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>(); - private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements + private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements Handler.Callback { private static final int MSG_STORAGE_STATE_CHANGED = 1; private static final int MSG_VOLUME_STATE_CHANGED = 2; @@ -374,7 +374,7 @@ public class StorageManager { mContext = context; mResolver = context.getContentResolver(); mLooper = looper; - mMountService = IMountService.Stub.asInterface(ServiceManager.getServiceOrThrow("mount")); + mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount")); } /** @@ -389,7 +389,7 @@ public class StorageManager { final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener, mLooper); try { - mMountService.registerListener(delegate); + mStorageManager.registerListener(delegate); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -410,7 +410,7 @@ public class StorageManager { final StorageEventListenerDelegate delegate = i.next(); if (delegate.mCallback == listener) { try { - mMountService.unregisterListener(delegate); + mStorageManager.unregisterListener(delegate); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -488,7 +488,7 @@ public class StorageManager { try { final String canonicalPath = new File(rawPath).getCanonicalPath(); final int nonce = mObbActionListener.addListener(listener); - mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce); + mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce); return true; } catch (IOException e) { throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e); @@ -523,7 +523,7 @@ public class StorageManager { try { final int nonce = mObbActionListener.addListener(listener); - mMountService.unmountObb(rawPath, force, mObbActionListener, nonce); + mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -540,7 +540,7 @@ public class StorageManager { Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); try { - return mMountService.isObbMounted(rawPath); + return mStorageManager.isObbMounted(rawPath); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -559,7 +559,7 @@ public class StorageManager { Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); try { - return mMountService.getMountedObbPath(rawPath); + return mStorageManager.getMountedObbPath(rawPath); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -568,7 +568,7 @@ public class StorageManager { /** {@hide} */ public @NonNull List<DiskInfo> getDisks() { try { - return Arrays.asList(mMountService.getDisks()); + return Arrays.asList(mStorageManager.getDisks()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -654,7 +654,7 @@ public class StorageManager { /** {@hide} */ public @NonNull List<VolumeInfo> getVolumes() { try { - return Arrays.asList(mMountService.getVolumes(0)); + return Arrays.asList(mStorageManager.getVolumes(0)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -664,7 +664,7 @@ public class StorageManager { public @NonNull List<VolumeInfo> getWritablePrivateVolumes() { try { final ArrayList<VolumeInfo> res = new ArrayList<>(); - for (VolumeInfo vol : mMountService.getVolumes(0)) { + for (VolumeInfo vol : mStorageManager.getVolumes(0)) { if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) { res.add(vol); } @@ -678,7 +678,7 @@ public class StorageManager { /** {@hide} */ public @NonNull List<VolumeRecord> getVolumeRecords() { try { - return Arrays.asList(mMountService.getVolumeRecords(0)); + return Arrays.asList(mStorageManager.getVolumeRecords(0)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -721,7 +721,7 @@ public class StorageManager { /** {@hide} */ public void mount(String volId) { try { - mMountService.mount(volId); + mStorageManager.mount(volId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -730,7 +730,7 @@ public class StorageManager { /** {@hide} */ public void unmount(String volId) { try { - mMountService.unmount(volId); + mStorageManager.unmount(volId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -739,7 +739,7 @@ public class StorageManager { /** {@hide} */ public void format(String volId) { try { - mMountService.format(volId); + mStorageManager.format(volId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -748,7 +748,7 @@ public class StorageManager { /** {@hide} */ public long benchmark(String volId) { try { - return mMountService.benchmark(volId); + return mStorageManager.benchmark(volId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -757,7 +757,7 @@ public class StorageManager { /** {@hide} */ public void partitionPublic(String diskId) { try { - mMountService.partitionPublic(diskId); + mStorageManager.partitionPublic(diskId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -766,7 +766,7 @@ public class StorageManager { /** {@hide} */ public void partitionPrivate(String diskId) { try { - mMountService.partitionPrivate(diskId); + mStorageManager.partitionPrivate(diskId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -775,7 +775,7 @@ public class StorageManager { /** {@hide} */ public void partitionMixed(String diskId, int ratio) { try { - mMountService.partitionMixed(diskId, ratio); + mStorageManager.partitionMixed(diskId, ratio); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -795,7 +795,7 @@ public class StorageManager { try { // TODO: switch to explicit wipe command when we have it, // for now rely on the fact that vfat format does a wipe - mMountService.partitionPublic(diskId); + mStorageManager.partitionPublic(diskId); } catch (Exception e) { Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e); } @@ -808,7 +808,7 @@ public class StorageManager { /** {@hide} */ public void setVolumeNickname(String fsUuid, String nickname) { try { - mMountService.setVolumeNickname(fsUuid, nickname); + mStorageManager.setVolumeNickname(fsUuid, nickname); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -817,7 +817,7 @@ public class StorageManager { /** {@hide} */ public void setVolumeInited(String fsUuid, boolean inited) { try { - mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0, + mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0, VolumeRecord.USER_FLAG_INITED); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -827,7 +827,7 @@ public class StorageManager { /** {@hide} */ public void setVolumeSnoozed(String fsUuid, boolean snoozed) { try { - mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0, + mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0, VolumeRecord.USER_FLAG_SNOOZED); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -837,7 +837,7 @@ public class StorageManager { /** {@hide} */ public void forgetVolume(String fsUuid) { try { - mMountService.forgetVolume(fsUuid); + mStorageManager.forgetVolume(fsUuid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -851,7 +851,7 @@ public class StorageManager { */ public String getPrimaryStorageUuid() { try { - return mMountService.getPrimaryStorageUuid(); + return mStorageManager.getPrimaryStorageUuid(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -865,7 +865,7 @@ public class StorageManager { */ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) { try { - mMountService.setPrimaryStorageUuid(volumeUuid, callback); + mStorageManager.setPrimaryStorageUuid(volumeUuid, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -982,7 +982,7 @@ public class StorageManager { /** {@hide} */ public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) { - final IMountService mountService = IMountService.Stub.asInterface( + final IStorageManager storageManager = IStorageManager.Stub.asInterface( ServiceManager.getService("mount")); try { String packageName = ActivityThread.currentOpPackageName(); @@ -1003,7 +1003,7 @@ public class StorageManager { if (uid <= 0) { return new StorageVolume[0]; } - return mountService.getVolumeList(uid, packageName, flags); + return storageManager.getVolumeList(uid, packageName, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1085,7 +1085,7 @@ public class StorageManager { /** {@hide} */ public void createUserKey(int userId, int serialNumber, boolean ephemeral) { try { - mMountService.createUserKey(userId, serialNumber, ephemeral); + mStorageManager.createUserKey(userId, serialNumber, ephemeral); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1094,7 +1094,7 @@ public class StorageManager { /** {@hide} */ public void destroyUserKey(int userId) { try { - mMountService.destroyUserKey(userId); + mStorageManager.destroyUserKey(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1103,7 +1103,7 @@ public class StorageManager { /** {@hide} */ public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) { try { - mMountService.unlockUserKey(userId, serialNumber, token, secret); + mStorageManager.unlockUserKey(userId, serialNumber, token, secret); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1112,7 +1112,7 @@ public class StorageManager { /** {@hide} */ public void lockUserKey(int userId) { try { - mMountService.lockUserKey(userId); + mStorageManager.lockUserKey(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1121,7 +1121,7 @@ public class StorageManager { /** {@hide} */ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) { try { - mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags); + mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1130,7 +1130,7 @@ public class StorageManager { /** {@hide} */ public void destroyUserStorage(String volumeUuid, int userId, int flags) { try { - mMountService.destroyUserStorage(volumeUuid, userId, flags); + mStorageManager.destroyUserStorage(volumeUuid, userId, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1138,17 +1138,17 @@ public class StorageManager { /** {@hide} */ public static boolean isUserKeyUnlocked(int userId) { - if (sMountService == null) { - sMountService = IMountService.Stub + if (sStorageManager == null) { + sStorageManager = IStorageManager.Stub .asInterface(ServiceManager.getService("mount")); } - if (sMountService == null) { + if (sStorageManager == null) { Slog.w(TAG, "Early during boot, assuming locked"); return false; } final long token = Binder.clearCallingIdentity(); try { - return sMountService.isUserKeyUnlocked(userId); + return sStorageManager.isUserKeyUnlocked(userId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } finally { @@ -1224,9 +1224,9 @@ public class StorageManager { } try { - IMountService mountService = IMountService.Stub.asInterface( + IStorageManager storageManager = IStorageManager.Stub.asInterface( ServiceManager.getService("mount")); - return mountService.getPasswordType() != CRYPT_TYPE_DEFAULT; + return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT; } catch (RemoteException e) { Log.e(TAG, "Error getting encryption type"); return false; @@ -1280,10 +1280,10 @@ public class StorageManager { /** {@hide} */ public static File maybeTranslateEmulatedPathToInternal(File path) { - final IMountService mountService = IMountService.Stub.asInterface( + final IStorageManager storageManager = IStorageManager.Stub.asInterface( ServiceManager.getService("mount")); try { - final VolumeInfo[] vols = mountService.getVolumes(0); + final VolumeInfo[] vols = storageManager.getVolumes(0); for (VolumeInfo vol : vols) { if ((vol.getType() == VolumeInfo.TYPE_EMULATED || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) { @@ -1303,7 +1303,7 @@ public class StorageManager { /** {@hide} */ public ParcelFileDescriptor mountAppFuse(String name) { try { - return mMountService.mountAppFuse(name); + return mStorageManager.mountAppFuse(name); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1319,7 +1319,7 @@ public class StorageManager { /** @hide */ public static final int CRYPT_TYPE_PIN = 3; - // Constants for the data available via MountService.getField. + // Constants for the data available via StorageManagerService.getField. /** @hide */ public static final String SYSTEM_LOCALE_KEY = "SystemLocale"; /** @hide */ diff --git a/core/java/android/os/storage/MountServiceInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 17aaef98c769..d102b194f86d 100644 --- a/core/java/android/os/storage/MountServiceInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -21,7 +21,7 @@ package android.os.storage; * * @hide Only for use within the system server. */ -public abstract class MountServiceInternal { +public abstract class StorageManagerInternal { /** * Policy that influences how external storage is mounted and reported. diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java index 8e7db31ef2f5..c8438870585a 100644 --- a/core/java/android/os/storage/StorageResultCode.java +++ b/core/java/android/os/storage/StorageResultCode.java @@ -18,7 +18,7 @@ package android.os.storage; /** * Class that provides access to constants returned from StorageManager - * and lower level MountService APIs. + * and lower level StorageManagerService APIs. * * @hide */ diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index 7b0d2a479702..46f2d387ac52 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -332,7 +332,7 @@ public final class StorageVolume implements Parcelable { * {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS}, * {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES}, * {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or - * {@link Environment#DIRECTORY_DOCUMENTS}, or {code null} to request access to the + * {@link Environment#DIRECTORY_DOCUMENTS}, or {@code null} to request access to the * entire volume. * @return intent to request access, or {@code null} if the requested directory is invalid for * that volume. diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 2dcf220b8ac4..383cae19e479 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -106,6 +106,22 @@ public final class DocumentsContract { public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI"; /** + * Sets the desired initial location visible to user when file chooser is shown. + * + * <p>Applicable to {@link Intent} with actions: + * <ul> + * <li>{@link Intent#ACTION_OPEN_DOCUMENT}</li> + * <li>{@link Intent#ACTION_CREATE_DOCUMENT}</li> + * <li>{@link Intent#ACTION_OPEN_DOCUMENT_TREE}</li> + * </ul> + * + * <p>Location should specify a document URI or a tree URI with document ID. If + * this URI identifies a non-directory, document navigator will attempt to use the parent + * of the document as the initial location. + */ + public static final String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI"; + + /** * Set this in a DocumentsUI intent to cause a package's own roots to be * excluded from the roots list. */ @@ -140,6 +156,10 @@ public final class DocumentsContract { private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES); /** {@hide} */ + public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY = + "com.android.externalstorage.documents"; + + /** {@hide} */ public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui"; /** @@ -683,7 +703,7 @@ public final class DocumentsContract { public static Uri buildHomeUri() { // TODO: Avoid this type of interpackage copying. Added here to avoid // direct coupling, but not ideal. - return DocumentsContract.buildRootUri("com.android.externalstorage.documents", "home"); + return DocumentsContract.buildRootUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY, "home"); } /** diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index b826584009c1..a280e594525e 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -41,6 +41,8 @@ public final class Downloads { public static final class Impl implements BaseColumns { private Impl() {} + public static final String AUTHORITY = "downloads"; + /** * The permission to access the download manager */ diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index de19f819295b..c4684e7af211 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -18,11 +18,13 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.UriPermission; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteException; @@ -32,17 +34,23 @@ import android.graphics.Matrix; import android.media.MiniThumbFile; import android.media.ThumbnailUtils; import android.net.Uri; +import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.service.media.CameraPrewarmService; import android.util.Log; +import libcore.io.IoUtils; + +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; +import java.util.List; /** * The Media provider contains meta data for all available media on both internal @@ -2297,4 +2305,86 @@ public final class MediaStore { } return null; } + + /** + * Gets a URI backed by a {@link DocumentsProvider} that points to the same media + * file as the specified mediaUri. This allows apps who have permissions to access + * media files in Storage Access Framework to perform file operations through that + * on media files. + * <p> + * Note: this method doesn't grant any URI permission. Callers need to obtain + * permission before calling this method. One way to obtain permission is through + * a 3-step process: + * <ol> + * <li>Call {@link android.os.storage.StorageManager#getStorageVolume(File)} to + * obtain the {@link android.os.storage.StorageVolume} of a media file;</li> + * + * <li>Invoke the intent returned by + * {@link android.os.storage.StorageVolume#createAccessIntent(String)} to + * obtain the access of the volume or one of its specific subdirectories;</li> + * + * <li>Check whether permission is granted and take persistent permission.</li> + * </ol> + * @param mediaUri the media URI which document URI is requested + * @return the document URI + */ + public static Uri getDocumentUri(Context context, Uri mediaUri) { + + try { + final ContentResolver resolver = context.getContentResolver(); + + final String path = getFilePath(resolver, mediaUri); + final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions(); + + return getDocumentUri(resolver, path, uriPermissions); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + private static String getFilePath(ContentResolver resolver, Uri mediaUri) + throws RemoteException { + + try (ContentProviderClient client = + resolver.acquireUnstableContentProviderClient(AUTHORITY)) { + final Cursor c = client.query( + mediaUri, + new String[]{ MediaColumns.DATA }, + null, /* selection */ + null, /* selectionArg */ + null /* sortOrder */); + + final String path; + try { + if (c.getCount() == 0) { + throw new IllegalStateException("Not found media file under URI: " + mediaUri); + } + + if (!c.moveToFirst()) { + throw new IllegalStateException("Failed to move cursor to the first item."); + } + + path = c.getString(0); + } finally { + IoUtils.closeQuietly(c); + } + + return path; + } + } + + private static Uri getDocumentUri( + ContentResolver resolver, String path, List<UriPermission> uriPermissions) + throws RemoteException { + + try (ContentProviderClient client = resolver.acquireUnstableContentProviderClient( + DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) { + final Bundle in = new Bundle(); + in.putParcelableList( + DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY + ".extra.uriPermissions", + uriPermissions); + final Bundle out = client.call("getDocumentId", path, in); + return out.getParcelable(DocumentsContract.EXTRA_URI); + } + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1b905a0204a4..0946906d122d 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -369,6 +369,22 @@ public final class Settings { "android.settings.WIFI_IP_SETTINGS"; /** + * Activity Action: Show settings to allow configuration of Wi-Fi saved networks. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_WIFI_SAVED_NETWORK_SETTINGS = + "android.settings.WIFI_SAVED_NETWORK_SETTINGS"; + + /** * Activity Action: Show settings to allow configuration of Bluetooth. * <p> * In some cases, a matching Activity may not exist, so ensure you @@ -4715,6 +4731,13 @@ public final class Settings { public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; /** + * The currently selected auto-fill service flattened ComponentName. + * @hide + */ + @TestApi + public static final String AUTO_FILL_SERVICE = "auto_fill_service"; + + /** * bluetooth HCI snoop log configuration * @hide */ @@ -5847,7 +5870,8 @@ public final class Settings { "search_per_source_concurrent_query_limit"; /** - * Whether or not alert sounds are played on MountService events. (0 = false, 1 = true) + * Whether or not alert sounds are played on StorageManagerService events. + * (0 = false, 1 = true) * @hide */ public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd"; @@ -6114,6 +6138,15 @@ public final class Settings { public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled"; /** + * Name of the service components that the current user has explicitly allowed to + * see and assist with all of the user's notifications. + * + * @hide + */ + public static final String ENABLED_NOTIFICATION_ASSISTANT = + "enabled_notification_assistant"; + + /** * Names of the service components that the current user has explicitly allowed to * see all of the user's notifications, separated by ':'. * @@ -8613,13 +8646,6 @@ public final class Settings { public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities"; /** - * @hide - * If not 0, the activity manager will implement a looser version of background - * check that is more compatible with existing apps. - */ - public static final String LENIENT_BACKGROUND_CHECK = "lenient_background_check"; - - /** * Use Dock audio output for media: * 0 = disabled * 1 = enabled @@ -8956,24 +8982,6 @@ public final class Settings { public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature"; /** - * A mask applied to the ephemeral hash to generate the hash prefix. - * <p> - * Type: int - * - * @hide - */ - public static final String EPHEMERAL_HASH_PREFIX_MASK = "ephemeral_hash_prefix_mask"; - - /** - * Number of hash prefixes to send during ephemeral resolution. - * <p> - * Type: int - * - * @hide - */ - public static final String EPHEMERAL_HASH_PREFIX_COUNT = "ephemeral_hash_prefix_count"; - - /** * The duration for caching uninstalled ephemeral apps. * <p> * Type: long diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java new file mode 100644 index 000000000000..5f27e3430bc4 --- /dev/null +++ b/core/java/android/service/autofill/AutoFillService.java @@ -0,0 +1,171 @@ +/* + * 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.service.autofill; + +import android.annotation.SdkConstant; +import android.app.Activity; +import android.app.Service; +import android.app.assist.AssistStructure; +import android.content.Intent; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.service.voice.VoiceInteractionSession; +import android.util.Log; + +import com.android.internal.os.HandlerCaller; +import com.android.internal.os.IResultReceiver; +import com.android.internal.os.SomeArgs; + +/** + * Top-level service of the current auto-fill service for a given user. + * + * <p>Apps providing auto-fill capabilities must extend this service. + */ +public abstract class AutoFillService extends Service { + + static final String TAG = "AutoFillService"; + static final boolean DEBUG = true; // TODO: set to false once stable + + /** + * The {@link Intent} that must be declared as handled by the service. + * To be supported, the service must also require the + * {@link android.Manifest.permission#BIND_AUTO_FILL} permission so + * that other applications can not abuse it. + */ + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; + + private static final int MSG_CONNECT = 1; + private static final int MSG_AUTO_FILL_ACTIVITY = 2; + private static final int MSG_DISCONNECT = 3; + + private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() { + @Override + public void send(int resultCode, Bundle resultData) throws RemoteException { + final AssistStructure structure = resultData + .getParcelable(VoiceInteractionSession.KEY_STRUCTURE); + + final IBinder binder = resultData + .getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK); + + mHandlerCaller + .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, binder).sendToTarget(); + } + + }; + + private final IAutoFillService mInterface = new IAutoFillService.Stub() { + @Override + public void onConnected() { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT)); + } + + @Override + public IResultReceiver getAssistReceiver() { + return mAssistReceiver; + } + + @Override + public void onDisconnected() { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT)); + } + }; + + private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() { + + @Override + public void executeMessage(Message msg) { + switch (msg.what) { + case MSG_CONNECT: { + onConnected(); + break; + } case MSG_AUTO_FILL_ACTIVITY: { + final SomeArgs args = (SomeArgs) msg.obj; + final AssistStructure structure = (AssistStructure) args.arg1; + final IBinder binder = (IBinder) args.arg2; + requestAutoFill(structure, binder); + break; + } case MSG_DISCONNECT: { + onDisconnected(); + break; + } default: { + Log.w(TAG, "MyCallbacks received invalid message type: " + msg); + } + } + } + }; + + private HandlerCaller mHandlerCaller; + + /** + * {@inheritDoc} + * + * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}. + */ + @Override + public void onCreate() { + super.onCreate(); + + mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true); + } + + @Override + public final IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + return mInterface.asBinder(); + } + Log.w(TAG, "Tried to bind to wrong intent: " + intent); + return null; + } + + /** + * Called when the Android System connects to service. + * + * <p>You should generally do initialization here rather than in {@link #onCreate}. + */ + public void onConnected() { + if (DEBUG) Log.d(TAG, "onConnected()"); + } + + /** + * Handles an auto-fill request. + * + * @param structure {@link Activity}'s view structure . + * @param cancellationSignal signal for observing cancel requests. + * @param callback object used to fulllfill the request. + */ + public abstract void onFillRequest(AssistStructure structure, + CancellationSignal cancellationSignal, FillCallback callback); + + private void requestAutoFill(AssistStructure structure, IBinder binder) { + final FillCallback callback = new FillCallback(binder); + // TODO: hook up the cancelationSignal + onFillRequest(structure, new CancellationSignal(), callback); + } + + /** + * Called when the Android System disconnects from the service. + * + * <p> At this point this service may no longer be an active {@link AutoFillService}. + */ + public void onDisconnected() { + if (DEBUG) Log.d(TAG, "onDisconnected()"); + } +} diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java new file mode 100644 index 000000000000..fe2161521b82 --- /dev/null +++ b/core/java/android/service/autofill/AutoFillServiceInfo.java @@ -0,0 +1,71 @@ +/* + * 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.service.autofill; + +import android.Manifest; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.os.RemoteException; + +/** @hide */ +public final class AutoFillServiceInfo { + + private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle) + throws PackageManager.NameNotFoundException { + try { + final ServiceInfo si = + AppGlobals.getPackageManager().getServiceInfo(comp, 0, userHandle); + if (si != null) { + return si; + } + } catch (RemoteException e) { + } + throw new PackageManager.NameNotFoundException(comp.toString()); + } + + private String mParseError; + + private ServiceInfo mServiceInfo; + + private AutoFillServiceInfo(ServiceInfo si) { + if (si == null) { + mParseError = "Service not available"; + return; + } + if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) { + mParseError = "Service does not require permission " + + Manifest.permission.BIND_AUTO_FILL; + return; + } + + mServiceInfo = si; + } + + public AutoFillServiceInfo(ComponentName comp, int userHandle) + throws PackageManager.NameNotFoundException { + this(getServiceInfoOrThrow(comp, userHandle)); + } + + public String getParseError() { + return mParseError; + } + + public ServiceInfo getServiceInfo() { + return mServiceInfo; + } +} diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java new file mode 100644 index 000000000000..23084409569f --- /dev/null +++ b/core/java/android/service/autofill/FillCallback.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.autofill; + +import static android.service.autofill.AutoFillService.DEBUG; +import static android.service.autofill.AutoFillService.TAG; + +import android.app.Activity; +import android.app.assist.AssistStructure.ViewNode; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Handles auto-fill requests from the {@link AutoFillService} into the {@link Activity} being + * auto-filled. + */ +public final class FillCallback { + + private final IAutoFillCallback mCallback; + + /** @hide */ + FillCallback(IBinder binder) { + mCallback = IAutoFillCallback.Stub.asInterface(binder); + } + + /** + * Auto-fills the {@link Activity}. + * + * @throws RuntimeException if an error occurred while auto-filling it. + */ + public void onSuccess(FillData data) { + if (DEBUG) Log.d(TAG, "onSuccess(): data=" + data); + + Preconditions.checkArgument(data != null, "data cannot be null"); + + try { + mCallback.autofill(data.asList()); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + public void onFailure(CharSequence message) { + if (DEBUG) Log.d(TAG, "onFailure(): message=" + message); + + Preconditions.checkArgument(message != null, "message cannot be null"); + + try { + mCallback.showError(message.toString()); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Data used to fill the fields of an {@link Activity}. + * + * <p>This class is immutable. + */ + public static final class FillData { + + private final List<FillableInputField> mList; + + private FillData(Builder builder) { + final int size = builder.mFields.size(); + final List<FillableInputField> list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(builder.mFields.valueAt(i)); + } + mList = Collections.unmodifiableList(list); + // TODO: use FastImmutableArraySet or a similar structure instead? + } + + /** + * Gets the response as a {@code List} so it can be used in a binder call. + */ + List<FillableInputField> asList() { + return mList; + } + + @Override + public String toString() { + return "[AutoFillResponse: " + mList + "]"; + } + + /** + * Builder for {@link FillData} objects. + * + * <p>Typical usage: + * + * <pre class="prettyprint"> + * FillCallback.FillData data = new FillCallback.FillData.Builder() + * .setTextField(id1, "value 1") + * .setTextField(id2, "value 2") + * .build() + * </pre> + */ + public static class Builder { + private final SparseArray<FillableInputField> mFields = new SparseArray<>(); + + /** + * Auto-fills a text field. + * + * @param id view id as returned by {@link ViewNode#getAutoFillId()}. + * @param text text to be auto-filled. + * @return same builder so it can be chained. + */ + public Builder setTextField(int id, String text) { + mFields.put(id, FillableInputField.forText(id, text)); + return this; + } + + /** + * Builds a new {@link FillData} instance. + */ + public FillData build() { + return new FillData(this); + } + } + } +} diff --git a/core/java/android/service/autofill/FillableInputField.java b/core/java/android/service/autofill/FillableInputField.java new file mode 100644 index 000000000000..62950b40e5e1 --- /dev/null +++ b/core/java/android/service/autofill/FillableInputField.java @@ -0,0 +1,99 @@ +/* + * 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.service.autofill; + +import android.app.assist.AssistStructure.ViewNode; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents a view field that can be auto-filled. + * + * <p>Currently only text-fields are supported, so the value of the field can be obtained through + * {@link #getValue()}. + * + * @hide + */ +public final class FillableInputField implements Parcelable { + + private final int mId; + private final String mValue; + + private FillableInputField(int id, String value) { + mId = id; + mValue = value; + } + + private FillableInputField(Parcel parcel) { + mId = parcel.readInt(); + mValue = parcel.readString(); + } + + /** + * Gets the view id as returned by {@link ViewNode#getAutoFillId()}. + */ + public int getId() { + return mId; + } + + /** + * Gets the value of this field. + */ + public String getValue() { + return mValue; + + } + + @Override + public String toString() { + return "[AutoFillField: " + mId + "=" + mValue + "]"; + } + + /** + * Creates an {@code AutoFillField} for a text field. + * + * @param id view id as returned by {@link ViewNode#getAutoFillId()}. + * @param text value to be auto-filled. + */ + public static FillableInputField forText(int id, String text) { + return new FillableInputField(id, text); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mId); + parcel.writeString(mValue); + } + + public static final Parcelable.Creator<FillableInputField> CREATOR = + new Parcelable.Creator<FillableInputField>() { + @Override + public FillableInputField createFromParcel(Parcel source) { + return new FillableInputField(source); + } + + @Override + public FillableInputField[] newArray(int size) { + return new FillableInputField[size]; + } + }; +} diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/service/autofill/IAutoFillCallback.aidl new file mode 100644 index 000000000000..d6d4f39651da --- /dev/null +++ b/core/java/android/service/autofill/IAutoFillCallback.aidl @@ -0,0 +1,27 @@ +/* + * 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.service.autofill; + +import java.util.List; + +/** + * @hide + */ +oneway interface IAutoFillCallback { + void autofill(in List values); + void showError(String message); +} diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl new file mode 100644 index 000000000000..76a25614f8ec --- /dev/null +++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl @@ -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. + */ + +package android.service.autofill; + +import android.os.Bundle; + +/** + * Mediator between apps being auto-filled and auto-fill service implementations. + * + * {@hide} + */ +oneway interface IAutoFillManagerService { + + /** + * Request auto-fill on the top activity of a given user. + * + * @param userId user handle. + * @param activityToken optional token of activity that needs to be on top. + */ + void requestAutoFill(int userId, IBinder activityToken); +} diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl new file mode 100644 index 000000000000..bb122e5eff7d --- /dev/null +++ b/core/java/android/service/autofill/IAutoFillService.aidl @@ -0,0 +1,31 @@ +/* + * 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.service.autofill; + +import android.app.assist.AssistStructure; +import android.os.Bundle; +import android.service.autofill.IAutoFillCallback; +import com.android.internal.os.IResultReceiver; + +/** + * @hide + */ +interface IAutoFillService { + oneway void onConnected(); + oneway void onDisconnected(); + IResultReceiver getAssistReceiver(); +} diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java index 455e1b25df18..813acc232289 100644 --- a/core/java/android/service/carrier/CarrierService.java +++ b/core/java/android/service/carrier/CarrierService.java @@ -107,12 +107,12 @@ public abstract class CarrierService extends Service { * <p> * Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. - * @see {@link android.telephony.TelephonyManager#hasCarrierPrivileges} + * or the calling app has carrier privileges. * * @param active Whether the carrier network change is or shortly will be * active. Set this value to true to begin showing * alternative UI and false to stop. + * @see android.telephony.TelephonyManager#hasCarrierPrivileges */ public final void notifyCarrierNetworkChange(boolean active) { try { diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java index 4a956c6a1d72..4b272e95f315 100644 --- a/core/java/android/service/notification/Adjustment.java +++ b/core/java/android/service/notification/Adjustment.java @@ -22,11 +22,8 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Ranking updates from the Ranker. - * - * @hide + * Ranking updates from the Assistant. */ -@SystemApi public final class Adjustment implements Parcelable { private final String mPackage; private final String mKey; diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index 8c359012bc51..f639c0de2044 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -28,7 +28,7 @@ oneway interface INotificationListener void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder, in NotificationRankingUpdate update); void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder, - in NotificationRankingUpdate update); + in NotificationRankingUpdate update, int reason); void onNotificationRankingUpdate(in NotificationRankingUpdate update); void onListenerHintsChanged(int hints); void onInterruptionFilterChanged(int interruptionFilter); @@ -38,5 +38,4 @@ oneway interface INotificationListener void onNotificationVisibilityChanged(String key, long time, boolean visible); void onNotificationClick(String key, long time); void onNotificationActionClick(String key, long time, int actionIndex); - void onNotificationRemovedReason(String key, long time, int reason); } diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java new file mode 100644 index 000000000000..4e00c643d749 --- /dev/null +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package android.service.notification; + +import android.annotation.SdkConstant; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import com.android.internal.os.SomeArgs; + +import java.util.List; + +/** + * A service that helps the user manage notifications. + */ +public abstract class NotificationAssistantService extends NotificationListenerService { + private static final String TAG = "NotificationAssistants"; + + /** + * The {@link Intent} that must be declared as handled by the service. + */ + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE + = "android.service.notification.NotificationAssistantService"; + + private Handler mHandler; + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + mHandler = new MyHandler(getContext().getMainLooper()); + } + + @Override + public final IBinder onBind(Intent intent) { + if (mWrapper == null) { + mWrapper = new NotificationAssistantServiceWrapper(); + } + return mWrapper; + } + + /** + * A notification was posted by an app. Called before alert. + * + * @param sbn the new notification + * @param importance the initial importance of the notification. + * @param user true if the initial importance reflects an explicit user preference. + * @return an adjustment or null to take no action, within 100ms. + */ + abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn, + int importance, boolean user); + + /** + * Updates a notification. N.B. this won’t cause + * an existing notification to alert, but might allow a future update to + * this notification to alert. + * + * @param adjustment the adjustment with an explanation + */ + public final void adjustNotification(Adjustment adjustment) { + if (!isBound()) return; + try { + getNotificationInterface().applyAdjustmentFromAssistantService(mWrapper, adjustment); + } catch (android.os.RemoteException ex) { + Log.v(TAG, "Unable to contact notification manager", ex); + } + } + + /** + * Updates existing notifications. Re-ranking won't occur until all adjustments are applied. + * N.B. this won’t cause an existing notification to alert, but might allow a future update to + * these notifications to alert. + * + * @param adjustments a list of adjustments with explanations + */ + public final void adjustNotifications(List<Adjustment> adjustments) { + if (!isBound()) return; + try { + getNotificationInterface().applyAdjustmentsFromAssistantService(mWrapper, adjustments); + } catch (android.os.RemoteException ex) { + Log.v(TAG, "Unable to contact notification manager", ex); + } + } + + private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper { + @Override + public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder, + int importance, boolean user) { + StatusBarNotification sbn; + try { + sbn = sbnHolder.get(); + } catch (RemoteException e) { + Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e); + return; + } + + SomeArgs args = SomeArgs.obtain(); + args.arg1 = sbn; + args.argi1 = importance; + args.argi2 = user ? 1 : 0; + mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED, + args).sendToTarget(); + } + } + + private final class MyHandler extends Handler { + public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1; + + public MyHandler(Looper looper) { + super(looper, null, false); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ON_NOTIFICATION_ENQUEUED: { + SomeArgs args = (SomeArgs) msg.obj; + StatusBarNotification sbn = (StatusBarNotification) args.arg1; + final int importance = args.argi1; + final boolean user = args.argi2 == 1; + args.recycle(); + Adjustment adjustment = onNotificationEnqueued(sbn, importance, user); + if (adjustment != null) { + adjustNotification(adjustment); + } + } break; + } + } + } +} diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index e606ebfbfee6..45011eb49905 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -77,6 +77,7 @@ import java.util.List; * </p> */ public abstract class NotificationListenerService extends Service { + // TAG = "NotificationListenerService[MySubclass]" private final String TAG = NotificationListenerService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; @@ -146,6 +147,48 @@ public abstract class NotificationListenerService extends Service { public static final int SUPPRESSED_EFFECT_SCREEN_ON = NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; + + // Notification cancellation reasons + + /** Notification was canceled by the status bar reporting a click. */ + public static final int REASON_DELEGATE_CLICK = 1; + /** Notification was canceled by the status bar reporting a user dismissal. */ + public static final int REASON_DELEGATE_CANCEL = 2; + /** Notification was canceled by the status bar reporting a user dismiss all. */ + public static final int REASON_DELEGATE_CANCEL_ALL = 3; + /** Notification was canceled by the status bar reporting an inflation error. */ + public static final int REASON_DELEGATE_ERROR = 4; + /** Notification was canceled by the package manager modifying the package. */ + public static final int REASON_PACKAGE_CHANGED = 5; + /** Notification was canceled by the owning user context being stopped. */ + public static final int REASON_USER_STOPPED = 6; + /** Notification was canceled by the user banning the package. */ + public static final int REASON_PACKAGE_BANNED = 7; + /** Notification was canceled by the app canceling this specific notification. */ + public static final int REASON_APP_CANCEL = 8; + /** Notification was canceled by the app cancelling all its notifications. */ + public static final int REASON_APP_CANCEL_ALL = 9; + /** Notification was canceled by a listener reporting a user dismissal. */ + public static final int REASON_LISTENER_CANCEL = 10; + /** Notification was canceled by a listener reporting a user dismiss all. */ + public static final int REASON_LISTENER_CANCEL_ALL = 11; + /** Notification was canceled because it was a member of a canceled group. */ + public static final int REASON_GROUP_SUMMARY_CANCELED = 12; + /** Notification was canceled because it was an invisible member of a group. */ + public static final int REASON_GROUP_OPTIMIZATION = 13; + /** Notification was canceled by the device administrator suspending the package. */ + public static final int REASON_PACKAGE_SUSPENDED = 14; + /** Notification was canceled by the owning managed profile being turned off. */ + public static final int REASON_PROFILE_TURNED_OFF = 15; + /** Autobundled summary notification was canceled because its group was unbundled */ + public static final int REASON_UNAUTOBUNDLED = 16; + /** Notification was canceled by the user banning the channel. */ + public static final int REASON_CHANNEL_BANNED = 17; + /** Notification was snoozed. */ + public static final int REASON_SNOOZED = 18; + /** Notification no longer visible because of user switch */ + public static final int REASON_USER_SWITCH = 19; + /** * The full trim of the StatusBarNotification including all its features. * @@ -282,6 +325,32 @@ public abstract class NotificationListenerService extends Service { onNotificationRemoved(sbn); } + + /** + * Implement this method to learn when notifications are removed and why. + * <p> + * This might occur because the user has dismissed the notification using system UI (or another + * notification listener) or because the app has withdrawn the notification. + * <p> + * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the + * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight + * fields such as {@link android.app.Notification#contentView} and + * {@link android.app.Notification#largeIcon}. However, all other fields on + * {@link StatusBarNotification}, sufficient to match this call with a prior call to + * {@link #onNotificationPosted(StatusBarNotification)}, will be intact. + * + ** @param sbn A data structure encapsulating at least the original information (tag and id) + * and source (package name) used to post the {@link android.app.Notification} that + * was just removed. + * @param rankingMap The current ranking map that can be used to retrieve ranking information + * for active notifications. + * @param reason see {@link #REASON_LISTENER_CANCEL}, etc. + */ + public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, + int reason) { + onNotificationRemoved(sbn, rankingMap); + } + /** * Implement this method to learn about when the listener is enabled and connected to * the notification manager. You are safe to call {@link #getActiveNotifications()} @@ -927,7 +996,7 @@ public abstract class NotificationListenerService extends Service { @Override public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder, - NotificationRankingUpdate update) { + NotificationRankingUpdate update, int reason) { StatusBarNotification sbn; try { sbn = sbnHolder.get(); @@ -941,6 +1010,7 @@ public abstract class NotificationListenerService extends Service { SomeArgs args = SomeArgs.obtain(); args.arg1 = sbn; args.arg2 = mRankingMap; + args.arg3 = reason; mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED, args).sendToTarget(); } @@ -1003,12 +1073,6 @@ public abstract class NotificationListenerService extends Service { throws RemoteException { // no-op in the listener } - - @Override - public void onNotificationRemovedReason(String key, long time, int reason) - throws RemoteException { - // no-op in the listener - } } private void applyUpdateLocked(NotificationRankingUpdate update) { @@ -1413,8 +1477,9 @@ public abstract class NotificationListenerService extends Service { SomeArgs args = (SomeArgs) msg.obj; StatusBarNotification sbn = (StatusBarNotification) args.arg1; RankingMap rankingMap = (RankingMap) args.arg2; + int reason = (int) args.arg3; args.recycle(); - onNotificationRemoved(sbn, rankingMap); + onNotificationRemoved(sbn, rankingMap, reason); } break; case MSG_ON_LISTENER_CONNECTED: { diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java deleted file mode 100644 index 928d5d847365..000000000000 --- a/core/java/android/service/notification/NotificationRankerService.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * 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. - */ - -package android.service.notification; - -import android.annotation.SdkConstant; -import android.annotation.SystemApi; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.RemoteException; -import android.util.Log; -import com.android.internal.os.SomeArgs; - -import java.util.List; - -/** - * A service that helps the user manage notifications. This class is only used to - * extend the framework service and may not be implemented by non-framework components. - * @hide - */ -@SystemApi -public abstract class NotificationRankerService extends NotificationListenerService { - private static final String TAG = "NotificationRankers"; - - /** - * The {@link Intent} that must be declared as handled by the service. - */ - @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) - public static final String SERVICE_INTERFACE - = "android.service.notification.NotificationRankerService"; - - /** Notification was canceled by the status bar reporting a click. */ - public static final int REASON_DELEGATE_CLICK = 1; - - /** Notification was canceled by the status bar reporting a user dismissal. */ - public static final int REASON_DELEGATE_CANCEL = 2; - - /** Notification was canceled by the status bar reporting a user dismiss all. */ - public static final int REASON_DELEGATE_CANCEL_ALL = 3; - - /** Notification was canceled by the status bar reporting an inflation error. */ - public static final int REASON_DELEGATE_ERROR = 4; - - /** Notification was canceled by the package manager modifying the package. */ - public static final int REASON_PACKAGE_CHANGED = 5; - - /** Notification was canceled by the owning user context being stopped. */ - public static final int REASON_USER_STOPPED = 6; - - /** Notification was canceled by the user banning the package. */ - public static final int REASON_PACKAGE_BANNED = 7; - - /** Notification was canceled by the app canceling this specific notification. */ - public static final int REASON_APP_CANCEL = 8; - - /** Notification was canceled by the app cancelling all its notifications. */ - public static final int REASON_APP_CANCEL_ALL = 9; - - /** Notification was canceled by a listener reporting a user dismissal. */ - public static final int REASON_LISTENER_CANCEL = 10; - - /** Notification was canceled by a listener reporting a user dismiss all. */ - public static final int REASON_LISTENER_CANCEL_ALL = 11; - - /** Notification was canceled because it was a member of a canceled group. */ - public static final int REASON_GROUP_SUMMARY_CANCELED = 12; - - /** Notification was canceled because it was an invisible member of a group. */ - public static final int REASON_GROUP_OPTIMIZATION = 13; - - /** Notification was canceled by the device administrator suspending the package. */ - public static final int REASON_PACKAGE_SUSPENDED = 14; - - /** Notification was canceled by the owning managed profile being turned off. */ - public static final int REASON_PROFILE_TURNED_OFF = 15; - - /** Autobundled summary notification was canceled because its group was unbundled */ - public static final int REASON_UNAUTOBUNDLED = 16; - - /** Notification was canceled by the user banning the channel. */ - public static final int REASON_CHANNEL_BANNED = 17; - - /** Notification was snoozed. */ - public static final int REASON_SNOOZED = 18; - - private Handler mHandler; - - /** @hide */ - @Override - public void registerAsSystemService(Context context, ComponentName componentName, - int currentUser) { - throw new UnsupportedOperationException("the ranker lifecycle is managed by the system."); - } - - /** @hide */ - @Override - public void unregisterAsSystemService() { - throw new UnsupportedOperationException("the ranker lifecycle is managed by the system."); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - mHandler = new MyHandler(getContext().getMainLooper()); - } - - @Override - public final IBinder onBind(Intent intent) { - if (mWrapper == null) { - mWrapper = new NotificationRankingServiceWrapper(); - } - return mWrapper; - } - - /** - * A notification was posted by an app. Called before alert. - * - * @param sbn the new notification - * @param importance the initial importance of the notification. - * @param user true if the initial importance reflects an explicit user preference. - * @return an adjustment or null to take no action, within 100ms. - */ - abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn, - int importance, boolean user); - - /** - * The visibility of a notification has changed. - * - * @param key the notification key - * @param time milliseconds since midnight, January 1, 1970 UTC. - * @param visible true if the notification became visible, false if hidden. - */ - public void onNotificationVisibilityChanged(String key, long time, boolean visible) - { - // Do nothing, Override this to collect visibility statistics. - } - - /** - * The user clicked on a notification. - * - * @param key the notification key - * @param time milliseconds since midnight, January 1, 1970 UTC. - */ - public void onNotificationClick(String key, long time) - { - // Do nothing, Override this to collect click statistics - } - - /** - * The user clicked on a notification action. - * - * @param key the notification key - * @param time milliseconds since midnight, January 1, 1970 UTC. - * @param actionIndex the index of the action button that was pressed. - */ - public void onNotificationActionClick(String key, long time, int actionIndex) - { - // Do nothing, Override this to collect action button click statistics - } - - /** - * A notification was removed. - - * @param key the notification key - * @param time milliseconds since midnight, January 1, 1970 UTC. - * @param reason see {@link #REASON_LISTENER_CANCEL}, etc. - */ - public void onNotificationRemoved(String key, long time, int reason) { - // Do nothing, Override this to collect dismissal statistics - } - - /** - * Updates a notification. N.B. this won’t cause - * an existing notification to alert, but might allow a future update to - * this notification to alert. - * - * @param adjustment the adjustment with an explanation - */ - public final void adjustNotification(Adjustment adjustment) { - if (!isBound()) return; - try { - getNotificationInterface().applyAdjustmentFromRankerService(mWrapper, adjustment); - } catch (android.os.RemoteException ex) { - Log.v(TAG, "Unable to contact notification manager", ex); - } - } - - /** - * Updates existing notifications. Re-ranking won't occur until all adjustments are applied. - * N.B. this won’t cause an existing notification to alert, but might allow a future update to - * these notifications to alert. - * - * @param adjustments a list of adjustments with explanations - */ - public final void adjustNotifications(List<Adjustment> adjustments) { - if (!isBound()) return; - try { - getNotificationInterface().applyAdjustmentsFromRankerService(mWrapper, adjustments); - } catch (android.os.RemoteException ex) { - Log.v(TAG, "Unable to contact notification manager", ex); - } - } - - private class NotificationRankingServiceWrapper extends NotificationListenerWrapper { - @Override - public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder, - int importance, boolean user) { - StatusBarNotification sbn; - try { - sbn = sbnHolder.get(); - } catch (RemoteException e) { - Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e); - return; - } - - SomeArgs args = SomeArgs.obtain(); - args.arg1 = sbn; - args.argi1 = importance; - args.argi2 = user ? 1 : 0; - mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED, - args).sendToTarget(); - } - - @Override - public void onNotificationVisibilityChanged(String key, long time, boolean visible) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = key; - args.arg2 = time; - args.argi1 = visible ? 1 : 0; - mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_VISIBILITY_CHANGED, - args).sendToTarget(); - } - - @Override - public void onNotificationClick(String key, long time) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = key; - args.arg2 = time; - mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_CLICK, - args).sendToTarget(); - } - - @Override - public void onNotificationActionClick(String key, long time, int actionIndex) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = key; - args.arg2 = time; - args.argi1 = actionIndex; - mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ACTION_CLICK, - args).sendToTarget(); - } - - @Override - public void onNotificationRemovedReason(String key, long time, int reason) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = key; - args.arg2 = time; - args.argi1 = reason; - mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED_REASON, - args).sendToTarget(); - } - } - - private final class MyHandler extends Handler { - public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1; - public static final int MSG_ON_NOTIFICATION_VISIBILITY_CHANGED = 2; - public static final int MSG_ON_NOTIFICATION_CLICK = 3; - public static final int MSG_ON_NOTIFICATION_ACTION_CLICK = 4; - public static final int MSG_ON_NOTIFICATION_REMOVED_REASON = 5; - - public MyHandler(Looper looper) { - super(looper, null, false); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_ON_NOTIFICATION_ENQUEUED: { - SomeArgs args = (SomeArgs) msg.obj; - StatusBarNotification sbn = (StatusBarNotification) args.arg1; - final int importance = args.argi1; - final boolean user = args.argi2 == 1; - args.recycle(); - Adjustment adjustment = onNotificationEnqueued(sbn, importance, user); - if (adjustment != null) { - adjustNotification(adjustment); - } - } break; - - case MSG_ON_NOTIFICATION_VISIBILITY_CHANGED: { - SomeArgs args = (SomeArgs) msg.obj; - final String key = (String) args.arg1; - final long time = (long) args.arg2; - final boolean visible = args.argi1 == 1; - args.recycle(); - onNotificationVisibilityChanged(key, time, visible); - } break; - - case MSG_ON_NOTIFICATION_CLICK: { - SomeArgs args = (SomeArgs) msg.obj; - final String key = (String) args.arg1; - final long time = (long) args.arg2; - args.recycle(); - onNotificationClick(key, time); - } break; - - case MSG_ON_NOTIFICATION_ACTION_CLICK: { - SomeArgs args = (SomeArgs) msg.obj; - final String key = (String) args.arg1; - final long time = (long) args.arg2; - final int actionIndex = args.argi1; - args.recycle(); - onNotificationActionClick(key, time, actionIndex); - } break; - - case MSG_ON_NOTIFICATION_REMOVED_REASON: { - SomeArgs args = (SomeArgs) msg.obj; - final String key = (String) args.arg1; - final long time = (long) args.arg2; - final int reason = args.argi1; - args.recycle(); - onNotificationRemoved(key, time, reason); - } break; - } - } - } -} diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index be0b47cc58ac..dfb6b8639912 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -17,6 +17,7 @@ package android.service.notification; import android.app.Notification; +import android.app.NotificationChannel; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -42,25 +43,21 @@ public class StatusBarNotification implements Parcelable { private final Notification notification; private final UserHandle user; private final long postTime; + private final NotificationChannel channel; private Context mContext; // used for inflation & icon expansion /** @hide */ - public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid, - int initialPid, int score, Notification notification, UserHandle user) { - this(pkg, opPkg, id, tag, uid, initialPid, score, notification, user, - System.currentTimeMillis()); - } - - /** @hide */ - public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid, - int initialPid, Notification notification, UserHandle user, String overrideGroupKey, - long postTime) { + public StatusBarNotification(String pkg, String opPkg, NotificationChannel channel, int id, + String tag, int uid, int initialPid, Notification notification, UserHandle user, + String overrideGroupKey, long postTime) { if (pkg == null) throw new NullPointerException(); if (notification == null) throw new NullPointerException(); + if (channel == null) throw new IllegalArgumentException(); this.pkg = pkg; this.opPkg = opPkg; + this.channel = channel; this.id = id; this.tag = tag; this.uid = uid; @@ -73,6 +70,7 @@ public class StatusBarNotification implements Parcelable { this.groupKey = groupKey(); } + @Deprecated public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid, int initialPid, int score, Notification notification, UserHandle user, long postTime) { @@ -90,6 +88,7 @@ public class StatusBarNotification implements Parcelable { this.postTime = postTime; this.key = key(); this.groupKey = groupKey(); + this.channel = null; } public StatusBarNotification(Parcel in) { @@ -113,6 +112,7 @@ public class StatusBarNotification implements Parcelable { } this.key = key(); this.groupKey = groupKey(); + this.channel = NotificationChannel.CREATOR.createFromParcel(in); } private String key() { @@ -182,6 +182,7 @@ public class StatusBarNotification implements Parcelable { } else { out.writeInt(0); } + this.channel.writeToParcel(out, flags); } public int describeContents() { @@ -208,14 +209,14 @@ public class StatusBarNotification implements Parcelable { public StatusBarNotification cloneLight() { final Notification no = new Notification(); this.notification.cloneInto(no, false); // light copy - return new StatusBarNotification(this.pkg, this.opPkg, + return new StatusBarNotification(this.pkg, this.opPkg, this.channel, this.id, this.tag, this.uid, this.initialPid, no, this.user, this.overrideGroupKey, this.postTime); } @Override public StatusBarNotification clone() { - return new StatusBarNotification(this.pkg, this.opPkg, + return new StatusBarNotification(this.pkg, this.opPkg, this.channel, this.id, this.tag, this.uid, this.initialPid, this.notification.clone(), this.user, this.overrideGroupKey, this.postTime); } @@ -335,6 +336,13 @@ public class StatusBarNotification implements Parcelable { } /** + * Returns the channel this notification was posted to. + */ + public NotificationChannel getNotificationChannel() { + return channel; + } + + /** * @hide */ public Context getPackageContext(Context context) { diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index e9bbc2de26cc..12aed251904f 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -119,6 +119,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public static final String KEY_CONTENT = "content"; /** @hide */ public static final String KEY_RECEIVER_EXTRAS = "receiverExtras"; + /** @hide */ + public static final String KEY_AUTO_FILL_CALLBACK = "autoFillCallback"; final Context mContext; final HandlerCaller mHandlerCaller; diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java index b3f2c2a5c447..c0948a6c138c 100644 --- a/core/java/android/text/Editable.java +++ b/core/java/android/text/Editable.java @@ -121,8 +121,10 @@ extends CharSequence, GetChars, Spannable, Appendable public InputFilter[] getFilters(); /** - * Factory used by TextView to create new Editables. You can subclass - * it to provide something other than SpannableStringBuilder. + * Factory used by TextView to create new {@link Editable Editables}. You can subclass + * it to provide something other than {@link SpannableStringBuilder}. + * + * @see android.widget.TextView#setEditableFactory(Factory) */ public static class Factory { private static Editable.Factory sInstance = new Editable.Factory(); diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index f9afcc7ac36c..fd6fc7dc0860 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -634,6 +634,17 @@ public abstract class Layout { } /** + * Return the total height of this layout. + * + * @param cap if true and max lines is set, returns the height of the layout at the max lines. + * + * @hide + */ + public int getHeight(boolean cap) { + return getHeight(); + } + + /** * Return the base alignment of this layout. */ public final Alignment getAlignment() { diff --git a/core/java/android/text/Spannable.java b/core/java/android/text/Spannable.java index ae5d356234b7..39b78eb056d3 100644 --- a/core/java/android/text/Spannable.java +++ b/core/java/android/text/Spannable.java @@ -46,15 +46,17 @@ extends Spanned public void removeSpan(Object what); /** - * Factory used by TextView to create new Spannables. You can subclass - * it to provide something other than SpannableString. + * Factory used by TextView to create new {@link Spannable Spannables}. You can subclass + * it to provide something other than {@link SpannableString}. + * + * @see android.widget.TextView#setSpannableFactory(Factory) */ public static class Factory { private static Spannable.Factory sInstance = new Spannable.Factory(); /** * Returns the standard Spannable Factory. - */ + */ public static Spannable.Factory getInstance() { return sInstance; } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index bdbe8b0f9a24..081be3afd6d3 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -836,7 +836,7 @@ public class StaticLayout extends Layout { here = endPos; breakIndex++; - if (mLineCount >= mMaximumVisibleLineCount) { + if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) { return; } } @@ -920,7 +920,25 @@ public class StaticLayout extends Layout { boolean firstLine = (j == 0); boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount); - boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd); + + if (ellipsize != null) { + // If there is only one line, then do any type of ellipsis except when it is MARQUEE + // if there are multiple lines, just allow END ellipsis on the last line + boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); + + boolean doEllipsis = + (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && + ellipsize != TextUtils.TruncateAt.MARQUEE) || + (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && + ellipsize == TextUtils.TruncateAt.END); + if (doEllipsis) { + calculateEllipsis(start, end, widths, widthStart, + ellipsisWidth, ellipsize, j, + textWidth, paint, forceEllipsis); + } + } + + boolean lastLine = mEllipsized || (end == bufEnd); if (firstLine) { if (trackPad) { @@ -944,7 +962,6 @@ public class StaticLayout extends Layout { } } - if (needMultiply && !lastLine) { double ex = (below - above) * (spacingmult - 1) + spacingadd; if (ex >= 0) { @@ -960,6 +977,15 @@ public class StaticLayout extends Layout { lines[off + TOP] = v; lines[off + DESCENT] = below + extra; + // special case for non-ellipsized last visible line when maxLines is set + // store the height as if it was ellipsized + if (!mEllipsized && currentLineIsTheLastVisibleOne) { + // below calculation as if it was the last line + int maxLineBelow = includePad ? bottom : below; + // similar to the calculation of v below, without the extra. + mMaxLineHeight = v + (maxLineBelow - above); + } + v += (below - above) + extra; lines[off + mColumns + START] = end; lines[off + mColumns + TOP] = v; @@ -981,23 +1007,6 @@ public class StaticLayout extends Layout { start - widthStart, end - start); } - if (ellipsize != null) { - // If there is only one line, then do any type of ellipsis except when it is MARQUEE - // if there are multiple lines, just allow END ellipsis on the last line - boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); - - boolean doEllipsis = - (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && - ellipsize != TextUtils.TruncateAt.MARQUEE) || - (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && - ellipsize == TextUtils.TruncateAt.END); - if (doEllipsis) { - calculateEllipsis(start, end, widths, widthStart, - ellipsisWidth, ellipsize, j, - textWidth, paint, forceEllipsis); - } - } - mLineCount++; return v; } @@ -1105,7 +1114,7 @@ public class StaticLayout extends Layout { } } } - + mEllipsized = true; mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart; mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount; } @@ -1243,6 +1252,25 @@ public class StaticLayout extends Layout { return mEllipsizedWidth; } + /** + * Return the total height of this layout. + * + * @param cap if true and max lines is set, returns the height of the layout at the max lines. + * + * @hide + */ + public int getHeight(boolean cap) { + if (cap && mLineCount >= mMaximumVisibleLineCount && mMaxLineHeight == -1 && + Log.isLoggable(TAG, Log.WARN)) { + Log.w(TAG, "maxLineHeight should not be -1. " + + " maxLines:" + mMaximumVisibleLineCount + + " lineCount:" + mLineCount); + } + + return cap && mLineCount >= mMaximumVisibleLineCount && mMaxLineHeight != -1 ? + mMaxLineHeight : super.getHeight(); + } + private static native long nNewBuilder(); private static native void nFreeBuilder(long nativePtr); private static native void nFinishBuilder(long nativePtr); @@ -1281,6 +1309,21 @@ public class StaticLayout extends Layout { private int mColumns; private int mEllipsizedWidth; + /** + * Keeps track if ellipsize is applied to the text. + */ + private boolean mEllipsized; + + /** + * If maxLines is set, ellipsize is not set, and the actual line count of text is greater than + * or equal to maxLine, this variable holds the ideal visual height of the maxLine'th line + * starting from the top of the layout. If maxLines is not set its value will be -1. + * + * The value is the same as getLineTop(maxLines) for ellipsized version where structurally no + * more than maxLines is contained. + */ + private int mMaxLineHeight = -1; + private static final int COLUMNS_NORMAL = 4; private static final int COLUMNS_ELLIPSIZE = 6; private static final int START = 0; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 03a2d6233967..c4118605b44c 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -850,6 +850,11 @@ class TextLine { int limit, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth) { + if (measureLimit < start || measureLimit > limit) { + throw new IndexOutOfBoundsException("measureLimit (" + measureLimit + ") is out of " + + "start (" + start + ") and limit (" + limit + ") bounds"); + } + // Case of an empty line, make sure we update fmi according to mPaint if (start == measureLimit) { TextPaint wp = mWorkPaint; diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index 479f49368191..6e4d78ded4f2 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -242,14 +242,20 @@ public class TransitionManager { Transition mTransition; ViewGroup mSceneRoot; + final ViewTreeObserver mViewTreeObserver; MultiListener(Transition transition, ViewGroup sceneRoot) { mTransition = transition; mSceneRoot = sceneRoot; + mViewTreeObserver = mSceneRoot.getViewTreeObserver(); } private void removeListeners() { - mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); + if (mViewTreeObserver.isAlive()) { + mViewTreeObserver.removeOnPreDrawListener(this); + } else { + mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); + } mSceneRoot.removeOnAttachStateChangeListener(this); } diff --git a/core/java/android/util/BootTimingsTraceLog.java b/core/java/android/util/BootTimingsTraceLog.java new file mode 100644 index 000000000000..2e4319cca0b9 --- /dev/null +++ b/core/java/android/util/BootTimingsTraceLog.java @@ -0,0 +1,64 @@ +/* + * 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.util; + +import android.os.Build; +import android.os.SystemClock; +import android.os.Trace; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * Helper class for reporting boot timing metrics. + * @hide + */ +public class BootTimingsTraceLog { + // Debug boot time for every step if it's non-user build. + private static final boolean DEBUG_BOOT_TIME = !"user".equals(Build.TYPE); + private final Deque<Pair<String, Long>> mStartTimes + = DEBUG_BOOT_TIME ? new ArrayDeque<>() : null; + private final String mTag; + private long mTraceTag; + + public BootTimingsTraceLog(String tag, long traceTag) { + mTag = tag; + mTraceTag = traceTag; + } + + public void traceBegin(String name) { + Trace.traceBegin(mTraceTag, name); + if (DEBUG_BOOT_TIME) { + mStartTimes.push(Pair.create(name, SystemClock.elapsedRealtime())); + } + } + + public void traceEnd() { + Trace.traceEnd(mTraceTag); + if (!DEBUG_BOOT_TIME) { + return; + } + if (mStartTimes.peek() == null) { + Slog.w(mTag, "traceEnd called more times than traceBegin"); + return; + } + Pair<String, Long> event = mStartTimes.pop(); + // Log the duration so it can be parsed by external tools for performance reporting + Slog.d(mTag, event.first + " took to complete: " + + (SystemClock.elapsedRealtime() - event.second) + "ms"); + } +} diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java index f4eb1328ffe3..1abc10d63509 100644 --- a/core/java/android/util/Half.java +++ b/core/java/android/util/Half.java @@ -16,31 +16,78 @@ package android.util; +import android.annotation.HalfFloat; + /** * <p>Half is a utility class to manipulate half-precision 16-bit * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a> - * floating point data types (also called fp16 or binary16). A half-precision - * float is stored in a short data type. A half-precision float can be - * created from or converted to single-precision floats.</p> + * floating point data types (also called fp16 or binary16). A half-precision float can be + * created from or converted to single-precision floats, and is stored in a short data type. + * To distinguish short values holding half-precision floats from regular short values, + * it is recommended to use the <code>@HalfFloat</code> annotation.</p> * * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p> * <ul> * <li>Sign bit: 1 bit</li> * <li>Exponent width: 5 bits</li> - * <li>Mantissa: 10 bits</li> + * <li>Significand: 10 bits</li> * </ul> * - * <p>The format is laid out thusly:</p> + * <p>The format is laid out as follows:</p> * <pre> * 1 11111 1111111111 * ^ --^-- -----^---- - * sign | |_______ mantissa + * sign | |_______ significand * | * -- exponent * </pre> * - * @hide + * <p>Half-precision floating points can be useful to save memory and/or + * bandwidth at the expense of range and precision when compared to single-precision + * floating points (fp32).</p> + * <p>To help you decide whether fp16 is the right storage type for you need, please + * refer to the table below that shows the available precision throughout the range of + * possible values. The <em>precision</em> column indicates the step size between two + * consecutive numbers in a specific part of the range.</p> + * + * <table summary="Precision of fp16 across the range"> + * <tr><th>Range start</th><th>Precision</th></tr> + * <tr><td>0</td><td>1 ⁄ 16,777,216</td></tr> + * <tr><td>1 ⁄ 16,384</td><td>1 ⁄ 16,777,216</td></tr> + * <tr><td>1 ⁄ 8,192</td><td>1 ⁄ 8,388,608</td></tr> + * <tr><td>1 ⁄ 4,096</td><td>1 ⁄ 4,194,304</td></tr> + * <tr><td>1 ⁄ 2,048</td><td>1 ⁄ 2,097,152</td></tr> + * <tr><td>1 ⁄ 1,024</td><td>1 ⁄ 1,048,576</td></tr> + * <tr><td>1 ⁄ 512</td><td>1 ⁄ 524,288</td></tr> + * <tr><td>1 ⁄ 256</td><td>1 ⁄ 262,144</td></tr> + * <tr><td>1 ⁄ 128</td><td>1 ⁄ 131,072</td></tr> + * <tr><td>1 ⁄ 64</td><td>1 ⁄ 65,536</td></tr> + * <tr><td>1 ⁄ 32</td><td>1 ⁄ 32,768</td></tr> + * <tr><td>1 ⁄ 16</td><td>1 ⁄ 16,384</td></tr> + * <tr><td>1 ⁄ 8</td><td>1 ⁄ 8,192</td></tr> + * <tr><td>1 ⁄ 4</td><td>1 ⁄ 4,096</td></tr> + * <tr><td>1 ⁄ 2</td><td>1 ⁄ 2,048</td></tr> + * <tr><td>1</td><td>1 ⁄ 1,024</td></tr> + * <tr><td>2</td><td>1 ⁄ 512</td></tr> + * <tr><td>4</td><td>1 ⁄ 256</td></tr> + * <tr><td>8</td><td>1 ⁄ 128</td></tr> + * <tr><td>16</td><td>1 ⁄ 64</td></tr> + * <tr><td>32</td><td>1 ⁄ 32</td></tr> + * <tr><td>64</td><td>1 ⁄ 16</td></tr> + * <tr><td>128</td><td>1 ⁄ 8</td></tr> + * <tr><td>256</td><td>1 ⁄ 4</td></tr> + * <tr><td>512</td><td>1 ⁄ 2</td></tr> + * <tr><td>1,024</td><td>1</td></tr> + * <tr><td>2,048</td><td>2</td></tr> + * <tr><td>4,096</td><td>4</td></tr> + * <tr><td>8,192</td><td>8</td></tr> + * <tr><td>16,384</td><td>16</td></tr> + * <tr><td>32,768</td><td>32</td></tr> + * </table> + * + * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p> */ +@SuppressWarnings("SimplifiableIfStatement") public final class Half { /** * The number of bits used to represent a half-precision float value. @@ -51,104 +98,410 @@ public final class Half { * Epsilon is the difference between 1.0 and the next value representable * by a half-precision floating-point. */ - public static final short EPSILON = (short) 0x1400; + public static final @HalfFloat short EPSILON = (short) 0x1400; + /** - * Smallest negative value a half-precision float may have. + * Maximum exponent a finite half-precision float may have. */ - public static final short LOWEST_VALUE = (short) 0xfbff; + public static final int MAX_EXPONENT = 15; /** - * Maximum exponent a finite half-precision float may have. + * Minimum exponent a normalized half-precision float may have. */ - public static final short MAX_EXPONENT = 15; + public static final int MIN_EXPONENT = -14; + /** - * Maximum positive finite value a half-precision float may have. + * Smallest negative value a half-precision float may have. */ - public static final short MAX_VALUE = (short) 0x7bff; + public static final @HalfFloat short LOWEST_VALUE = (short) 0xfbff; /** - * Minimum exponent a normalized half-precision float may have. + * Maximum positive finite value a half-precision float may have. */ - public static final short MIN_EXPONENT = -14; + public static final @HalfFloat short MAX_VALUE = (short) 0x7bff; /** * Smallest positive normal value a half-precision float may have. */ - public static final short MIN_NORMAL = (short) 0x0400; + public static final @HalfFloat short MIN_NORMAL = (short) 0x0400; /** * Smallest positive non-zero value a half-precision float may have. */ - public static final short MIN_VALUE = (short) 0x0001; + public static final @HalfFloat short MIN_VALUE = (short) 0x0001; /** * A Not-a-Number representation of a half-precision float. */ - public static final short NaN = (short) 0x7e00; + public static final @HalfFloat short NaN = (short) 0x7e00; /** * Negative infinity of type half-precision float. */ - public static final short NEGATIVE_INFINITY = (short) 0xfc00; + public static final @HalfFloat short NEGATIVE_INFINITY = (short) 0xfc00; /** * Negative 0 of type half-precision float. */ - public static final short NEGATIVE_ZERO = (short) 0x8000; + public static final @HalfFloat short NEGATIVE_ZERO = (short) 0x8000; /** * Positive infinity of type half-precision float. */ - public static final short POSITIVE_INFINITY = (short) 0x7c00; + public static final @HalfFloat short POSITIVE_INFINITY = (short) 0x7c00; /** * Positive 0 of type half-precision float. */ - public static final short POSITIVE_ZERO = (short) 0x0000; + public static final @HalfFloat short POSITIVE_ZERO = (short) 0x0000; - private static final int FP16_SIGN_SHIFT = 15; - private static final int FP16_EXPONENT_SHIFT = 10; - private static final int FP16_EXPONENT_MASK = 0x1f; - private static final int FP16_MANTISSA_MASK = 0x3ff; - private static final int FP16_EXPONENT_BIAS = 15; + private static final int FP16_SIGN_SHIFT = 15; + private static final int FP16_SIGN_MASK = 0x8000; + private static final int FP16_EXPONENT_SHIFT = 10; + private static final int FP16_EXPONENT_MASK = 0x1f; + private static final int FP16_SIGNIFICAND_MASK = 0x3ff; + private static final int FP16_EXPONENT_BIAS = 15; + private static final int FP16_COMBINED = 0x7fff; + private static final int FP16_EXPONENT_MAX = 0x7c00; - private static final int FP32_SIGN_SHIFT = 31; - private static final int FP32_EXPONENT_SHIFT = 23; - private static final int FP32_EXPONENT_MASK = 0xff; - private static final int FP32_MANTISSA_MASK = 0x7fffff; - private static final int FP32_EXPONENT_BIAS = 127; + private static final int FP32_SIGN_SHIFT = 31; + private static final int FP32_EXPONENT_SHIFT = 23; + private static final int FP32_EXPONENT_MASK = 0xff; + private static final int FP32_SIGNIFICAND_MASK = 0x7fffff; + private static final int FP32_EXPONENT_BIAS = 127; - private static final int FP32_DENORMAL_MAGIC = 126 << 23; - private static final float FP32_DENORMAL_FLOAT = - Float.intBitsToFloat(FP32_DENORMAL_MAGIC); + private static final int FP32_DENORMAL_MAGIC = 126 << 23; + private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC); private Half() { } /** + * Returns the first parameter with the sign of the second parameter. + * This method treats NaNs as having a sign. + * + * @param magnitude A half-precision float value providing the magnitude of the result + * @param sign A half-precision float value providing the sign of the result + * @return A value with the magnitude of the first parameter and the sign + * of the second parameter + */ + public static @HalfFloat short copySign(@HalfFloat short magnitude, @HalfFloat short sign) { + return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED)); + } + + /** + * Returns the absolute value of the specified half-precision float. + * Special values are handled in the following ways: + * <ul> + * <li>If the specified half-precision float is NaN, the result is NaN</li> + * <li>If the specified half-precision float is zero (negative or positive), + * the result is positive zero (see {@link #POSITIVE_ZERO})</li> + * <li>If the specified half-precision float is infinity (negative or positive), + * the result is positive infinity (see {@link #POSITIVE_INFINITY})</li> + * </ul> + * + * @param h A half-precision float value + * @return The absolute value of the specified half-precision float + */ + public static @HalfFloat short abs(@HalfFloat short h) { + return (short) (h & FP16_COMBINED); + } + + /** + * Returns the closest integral half-precision float value to the specified + * half-precision float value. Special values are handled in the + * following ways: + * <ul> + * <li>If the specified half-precision float is NaN, the result is NaN</li> + * <li>If the specified half-precision float is infinity (negative or positive), + * the result is infinity (with the same sign)</li> + * <li>If the specified half-precision float is zero (negative or positive), + * the result is zero (with the same sign)</li> + * </ul> + * + * @param h A half-precision float value + * @return The value of the specified half-precision float rounded to the nearest + * half-precision float value + */ + public static @HalfFloat short round(@HalfFloat short h) { + int bits = h & 0xffff; + int e = bits & 0x7fff; + int result = bits; + + if (e < 0x3c00) { + result &= FP16_SIGN_MASK; + result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0)); + } else if (e < 0x6400) { + e = 25 - (e >> 10); + int mask = (1 << e) - 1; + result += (1 << (e - 1)); + result &= ~mask; + } + + return (short) result; + } + + /** + * Returns the smallest half-precision float value toward negative infinity + * greater than or equal to the specified half-precision float value. + * Special values are handled in the following ways: + * <ul> + * <li>If the specified half-precision float is NaN, the result is NaN</li> + * <li>If the specified half-precision float is infinity (negative or positive), + * the result is infinity (with the same sign)</li> + * <li>If the specified half-precision float is zero (negative or positive), + * the result is zero (with the same sign)</li> + * </ul> + * + * @param h A half-precision float value + * @return The smallest half-precision float value toward negative infinity + * greater than or equal to the specified half-precision float value + */ + public static @HalfFloat short ceil(@HalfFloat short h) { + int bits = h & 0xffff; + int e = bits & 0x7fff; + int result = bits; + + if (e < 0x3c00) { + result &= FP16_SIGN_MASK; + result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0)); + } else if (e < 0x6400) { + e = 25 - (e >> 10); + int mask = (1 << e) - 1; + result += mask & ((bits >> 15) - 1); + result &= ~mask; + } + + return (short) result; + } + + /** + * Returns the largest half-precision float value toward positive infinity + * less than or equal to the specified half-precision float value. + * Special values are handled in the following ways: + * <ul> + * <li>If the specified half-precision float is NaN, the result is NaN</li> + * <li>If the specified half-precision float is infinity (negative or positive), + * the result is infinity (with the same sign)</li> + * <li>If the specified half-precision float is zero (negative or positive), + * the result is zero (with the same sign)</li> + * </ul> + * + * @param h A half-precision float value + * @return The largest half-precision float value toward positive infinity + * less than or equal to the specified half-precision float value + */ + public static @HalfFloat short floor(@HalfFloat short h) { + int bits = h & 0xffff; + int e = bits & 0x7fff; + int result = bits; + + if (e < 0x3c00) { + result &= FP16_SIGN_MASK; + result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0); + } else if (e < 0x6400) { + e = 25 - (e >> 10); + int mask = (1 << e) - 1; + result += mask & -(bits >> 15); + result &= ~mask; + } + + return (short) result; + } + + /** + * Returns the truncated half-precision float value of the specified + * half-precision float value. Special values are handled in the following ways: + * <ul> + * <li>If the specified half-precision float is NaN, the result is NaN</li> + * <li>If the specified half-precision float is infinity (negative or positive), + * the result is infinity (with the same sign)</li> + * <li>If the specified half-precision float is zero (negative or positive), + * the result is zero (with the same sign)</li> + * </ul> + * + * @param h A half-precision float value + * @return The truncated half-precision float value of the specified + * half-precision float value + */ + public static @HalfFloat short trunc(@HalfFloat short h) { + int bits = h & 0xffff; + int e = bits & 0x7fff; + int result = bits; + + if (e < 0x3c00) { + result &= FP16_SIGN_MASK; + } else if (e < 0x6400) { + e = 25 - (e >> 10); + int mask = (1 << e) - 1; + result &= ~mask; + } + + return (short) result; + } + + /** + * Returns the smaller of two half-precision float values (the value closest + * to negative infinity). Special values are handled in the following ways: + * <ul> + * <li>If either value is NaN, the result is NaN</li> + * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li> + * </ul> + * + * @param x The first half-precision value + * @param y The second half-precision value + * @return The smaller of the two specified half-precision values + */ + public static @HalfFloat short min(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; + + if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) { + return (x & FP16_SIGN_MASK) != 0 ? x : y; + } + + return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < + ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; + } + + /** + * Returns the larger of two half-precision float values (the value closest + * to positive infinity). Special values are handled in the following ways: + * <ul> + * <li>If either value is NaN, the result is NaN</li> + * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li> + * </ul> + * + * @param x The first half-precision value + * @param y The second half-precision value + * + * @return The larger of the two specified half-precision values + */ + public static @HalfFloat short max(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; + + if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) { + return (x & FP16_SIGN_MASK) != 0 ? y : x; + } + + return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > + ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; + } + + /** + * Returns true if the first half-precision float value is less (smaller + * toward negative infinity) than the second half-precision float value. + * If either of the values is NaN, the result is false. + * + * @param x The first half-precision value + * @param y The second half-precision value + * + * @return True if x is less than y, false otherwise + */ + public static boolean less(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + + return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < + ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + } + + /** + * Returns true if the first half-precision float value is less (smaller + * toward negative infinity) than or equal to the second half-precision + * float value. If either of the values is NaN, the result is false. + * + * @param x The first half-precision value + * @param y The second half-precision value + * + * @return True if x is less than or equal to y, false otherwise + */ + public static boolean lessEquals(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + + return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <= + ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + } + + /** + * Returns true if the first half-precision float value is greater (larger + * toward positive infinity) than the second half-precision float value. + * If either of the values is NaN, the result is false. + * + * @param x The first half-precision value + * @param y The second half-precision value + * + * @return True if x is greater than y, false otherwise + */ + public static boolean greater(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + + return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > + ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + } + + /** + * Returns true if the first half-precision float value is greater (larger + * toward positive infinity) than or equal to the second half-precision float + * value. If either of the values is NaN, the result is false. + * + * @param x The first half-precision value + * @param y The second half-precision value + * + * @return True if x is greater than y, false otherwise + */ + public static boolean greaterEquals(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + + return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >= + ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + } + + /** + * Returns true if the two half-precision float values are equal. + * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO} + * and {@link #NEGATIVE_ZERO} are considered equal. + * + * @param x The first half-precision value + * @param y The second half-precision value + * + * @return True if x is equal to y, false otherwise + */ + public static boolean equals(@HalfFloat short x, @HalfFloat short y) { + if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; + + return x == y || ((x | y) & FP16_COMBINED) == 0; + } + + /** * Returns the sign of the specified half-precision float. * * @param h A half-precision float value * @return 1 if the value is positive, -1 if the value is negative */ - public static int getSign(short h) { - return (h >>> FP16_SIGN_SHIFT) == 0 ? 1 : -1; + public static int getSign(@HalfFloat short h) { + return (h & FP16_SIGN_MASK) == 0 ? 1 : -1; } /** * Returns the unbiased exponent used in the representation of * the specified half-precision float value. if the value is NaN * or infinite, this* method returns {@link #MAX_EXPONENT} + 1. - * If the argument is* 0 or denormal, this method returns - * {@link #MIN_EXPONENT} - 1. + * If the argument is 0 or a subnormal representation, this method + * returns {@link #MIN_EXPONENT} - 1. * * @param h A half-precision float value * @return The unbiased exponent of the specified value */ - public static int getExponent(short h) { + public static int getExponent(@HalfFloat short h) { return ((h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK) - FP16_EXPONENT_BIAS; } /** - * Returns the mantissa, or significand, used in the representation + * Returns the significand, or mantissa, used in the representation * of the specified half-precision float value. * * @param h A half-precision float value - * @return The mantissa, or significand, of the specified vlaue + * @return The significand, or significand, of the specified vlaue */ - public static int getMantissa(short h) { - return h & FP16_MANTISSA_MASK; + public static int getSignificand(@HalfFloat short h) { + return h & FP16_SIGNIFICAND_MASK; } /** @@ -159,10 +512,8 @@ public final class Half { * @return true if the value is positive infinity or negative infinity, * false otherwise */ - public static boolean isInfinite(short h) { - int e = (h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (h ) & FP16_MANTISSA_MASK; - return e == 0x1f && m == 0; + public static boolean isInfinite(@HalfFloat short h) { + return (h & FP16_COMBINED) == FP16_EXPONENT_MAX; } /** @@ -172,10 +523,22 @@ public final class Half { * @param h A half-precision float value * @return true if the value is a NaN, false otherwise */ - public static boolean isNaN(short h) { - int e = (h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (h ) & FP16_MANTISSA_MASK; - return e == 0x1f && m != 0; + public static boolean isNaN(@HalfFloat short h) { + return (h & FP16_COMBINED) > FP16_EXPONENT_MAX; + } + + /** + * Returns true if the specified half-precision float value is normalized + * (does not have a subnormal representation). If the specified value is + * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY}, + * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal + * number, this method returns false. + * + * @param h A half-precision float value + * @return true if the value is normalized, false otherwise + */ + public static boolean isNormalized(@HalfFloat short h) { + return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX; } /** @@ -193,11 +556,11 @@ public final class Half { * @param h The half-precision float value to convert to single-precision * @return A normalized single-precision float value */ - public static float toFloat(short h) { + public static float toFloat(@HalfFloat short h) { int bits = h & 0xffff; - int s = (bits >>> FP16_SIGN_SHIFT ); + int s = bits & FP16_SIGN_MASK; int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (bits ) & FP16_MANTISSA_MASK; + int m = (bits ) & FP16_SIGNIFICAND_MASK; int outE = 0; int outM = 0; @@ -218,7 +581,7 @@ public final class Half { } } - int out = (s << FP32_SIGN_SHIFT) | (outE << FP32_EXPONENT_SHIFT) | outM; + int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM; return Float.intBitsToFloat(out); } @@ -245,11 +608,11 @@ public final class Half { * @return A half-precision float value */ @SuppressWarnings("StatementWithEmptyBody") - public static short valueOf(float f) { + public static @HalfFloat short valueOf(float f) { int bits = Float.floatToRawIntBits(f); int s = (bits >>> FP32_SIGN_SHIFT ); int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK; - int m = (bits ) & FP32_MANTISSA_MASK; + int m = (bits ) & FP32_SIGNIFICAND_MASK; int outE = 0; int outM = 0; @@ -278,14 +641,12 @@ public final class Half { // Round to nearest "0.5" up int out = (outE << FP16_EXPONENT_SHIFT) | outM; out++; - out |= (s << FP16_SIGN_SHIFT); - return (short) out; + return (short) (out | (s << FP16_SIGN_SHIFT)); } } } - int out = (s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM; - return (short) out; + return (short) ((s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM); } /** @@ -297,7 +658,7 @@ public final class Half { * @param h A half-precision float value * @return A string representation of the specified value */ - public static String toString(short h) { + public static String toString(@HalfFloat short h) { return Float.toString(toFloat(h)); } @@ -311,33 +672,33 @@ public final class Half { * <li>If the value is inifinity, the string is <code>"Infinity"</code></li> * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li> * <li>If the value has a normalized representation, the exponent and - * mantissa are represented in the string in two fields. The mantissa starts - * with <code>"0x1."</code> followed by its lowercase hexadecimal + * significand are represented in the string in two fields. The significand + * starts with <code>"0x1."</code> followed by its lowercase hexadecimal * representation. Trailing zeroes are removed unless all digits are 0, then - * a single zero is used. The mantissa representation is followed by the + * a single zero is used. The significand representation is followed by the * exponent, represented by <code>"p"</code>, itself followed by a decimal * string of the unbiased exponent</li> - * <li>If the value has a denormal representation, the mantissa starts + * <li>If the value has a subnormal representation, the significand starts * with <code>"0x0."</code> followed by its lowercase hexadecimal * representation. Trailing zeroes are removed unless all digits are 0, then - * a single zero is used. The mantissa representation is followed by the + * a single zero is used. The significand representation is followed by the * exponent, represented by <code>"p-14"</code></li> * </ul> * * @param h A half-precision float value * @return A hexadecimal string representation of the specified value */ - public static String toHexString(short h) { + public static String toHexString(@HalfFloat short h) { StringBuilder o = new StringBuilder(); int bits = h & 0xffff; int s = (bits >>> FP16_SIGN_SHIFT ); int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (bits ) & FP16_MANTISSA_MASK; + int m = (bits ) & FP16_SIGNIFICAND_MASK; if (e == 0x1f) { // Infinite or NaN if (m == 0) { - if (s == 1) o.append('-'); + if (s != 0) o.append('-'); o.append("Infinity"); } else { o.append("NaN"); @@ -349,14 +710,14 @@ public final class Half { o.append("0x0.0p0"); } else { o.append("0x0."); - String mantissa = Integer.toHexString(m); - o.append(mantissa.replaceFirst("0{2,}$", "")); + String significand = Integer.toHexString(m); + o.append(significand.replaceFirst("0{2,}$", "")); o.append("p-14"); } } else { o.append("0x1."); - String mantissa = Integer.toHexString(m); - o.append(mantissa.replaceFirst("0{2,}$", "")); + String significand = Integer.toHexString(m); + o.append(significand.replaceFirst("0{2,}$", "")); o.append('p'); o.append(Integer.toString(e - FP16_EXPONENT_BIAS)); } diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl index a81eef831f4e..d59be02c7371 100644 --- a/core/java/android/view/IPinnedStackController.aidl +++ b/core/java/android/view/IPinnedStackController.aidl @@ -32,6 +32,11 @@ interface IPinnedStackController { oneway void setInInteractiveMode(boolean inInteractiveMode); /** + * Notifies the controller that the PIP is currently minimized. + */ + oneway void setIsMinimized(boolean isMinimized); + + /** * Notifies the controller that the desired snap mode is to the closest edge. */ oneway void setSnapToEdge(boolean snapToEdge); 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/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 0bb84cca174a..5012215cf55b 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.IntDef; import android.annotation.NonNull; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -921,7 +921,7 @@ public final class ThreadedRenderer { private static void initSched(Context context, long renderProxy) { try { int tid = nGetRenderThreadTid(renderProxy); - ActivityManagerNative.getDefault().setRenderThread(tid); + ActivityManager.getService().setRenderThread(tid); } catch (Throwable t) { Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 441f3302994f..02a85216cc20 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6703,6 +6703,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { structure.setId(id, null, null, null); } + + // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to + // reuse the accessibility id to save space. + structure.setAutoFillId(getAccessibilityViewId()); + structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); if (!hasIdentityMatrix()) { structure.setTransformation(getMatrix()); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5a6cf7dfaa23..1ff8fb0bd8ee 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -26,7 +26,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import android.Manifest; import android.animation.LayoutTransition; import android.annotation.NonNull; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ResourcesManager; import android.content.ClipData; import android.content.ClipDescription; @@ -5611,6 +5611,13 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Notify that the window title changed + */ + public void onWindowTitleChanged() { + mAttachInfo.mForceReportNewAttributes = true; + } + public void handleDispatchWindowShown() { mAttachInfo.mTreeObserver.dispatchOnWindowShown(); } @@ -7077,7 +7084,7 @@ public final class ViewRootImpl implements ViewParent, private static int checkCallingPermission(String permission) { try { - return ActivityManagerNative.getDefault().checkPermission( + return ActivityManager.getService().checkPermission( permission, Binder.getCallingPid(), Binder.getCallingUid()); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 2e4ba74159f9..e9ff9d0edba6 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -275,4 +275,7 @@ public abstract class ViewStructure { /** @hide */ public abstract Rect getTempRect(); + + /** @hide */ + public abstract void setAutoFillId(int autoFillId); } diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java index ec852e88b17e..85d10f199218 100644 --- a/core/java/android/view/ViewStub.java +++ b/core/java/android/view/ViewStub.java @@ -142,11 +142,17 @@ public final class ViewStub extends View { * @see #getInflatedId() * @attr ref android.R.styleable#ViewStub_inflatedId */ - @android.view.RemotableViewMethod + @android.view.RemotableViewMethod(asyncImpl = "setInflatedIdAsync") public void setInflatedId(@IdRes int inflatedId) { mInflatedId = inflatedId; } + /** @hide **/ + public Runnable setInflatedIdAsync(@IdRes int inflatedId) { + mInflatedId = inflatedId; + return null; + } + /** * Returns the layout resource that will be used by {@link #setVisibility(int)} or * {@link #inflate()} to replace this StubbedView @@ -176,11 +182,17 @@ public final class ViewStub extends View { * @see #inflate() * @attr ref android.R.styleable#ViewStub_layout */ - @android.view.RemotableViewMethod + @android.view.RemotableViewMethod(asyncImpl = "setLayoutResourceAsync") public void setLayoutResource(@LayoutRes int layoutResource) { mLayoutResource = layoutResource; } + /** @hide **/ + public Runnable setLayoutResourceAsync(@LayoutRes int layoutResource) { + mLayoutResource = layoutResource; + return null; + } + /** * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null} * to use the default. @@ -220,7 +232,7 @@ public final class ViewStub extends View { * @see #inflate() */ @Override - @android.view.RemotableViewMethod + @android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync") public void setVisibility(int visibility) { if (mInflatedViewRef != null) { View view = mInflatedViewRef.get(); @@ -237,6 +249,43 @@ public final class ViewStub extends View { } } + /** @hide **/ + public Runnable setVisibilityAsync(int visibility) { + if (visibility == VISIBLE || visibility == INVISIBLE) { + ViewGroup parent = (ViewGroup) getParent(); + return new ViewReplaceRunnable(inflateViewNoAdd(parent)); + } else { + return null; + } + } + + private View inflateViewNoAdd(ViewGroup parent) { + final LayoutInflater factory; + if (mInflater != null) { + factory = mInflater; + } else { + factory = LayoutInflater.from(mContext); + } + final View view = factory.inflate(mLayoutResource, parent, false); + + if (mInflatedId != NO_ID) { + view.setId(mInflatedId); + } + return view; + } + + private void replaceSelfWithView(View view, ViewGroup parent) { + final int index = parent.indexOfChild(this); + parent.removeViewInLayout(this); + + final ViewGroup.LayoutParams layoutParams = getLayoutParams(); + if (layoutParams != null) { + parent.addView(view, index, layoutParams); + } else { + parent.addView(view, index); + } + } + /** * Inflates the layout resource identified by {@link #getLayoutResource()} * and replaces this StubbedView in its parent by the inflated layout resource. @@ -250,31 +299,10 @@ public final class ViewStub extends View { if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; - final LayoutInflater factory; - if (mInflater != null) { - factory = mInflater; - } else { - factory = LayoutInflater.from(mContext); - } - final View view = factory.inflate(mLayoutResource, parent, - false); - - if (mInflatedId != NO_ID) { - view.setId(mInflatedId); - } - - final int index = parent.indexOfChild(this); - parent.removeViewInLayout(this); - - final ViewGroup.LayoutParams layoutParams = getLayoutParams(); - if (layoutParams != null) { - parent.addView(view, index, layoutParams); - } else { - parent.addView(view, index); - } - - mInflatedViewRef = new WeakReference<View>(view); + final View view = inflateViewNoAdd(parent); + replaceSelfWithView(view, parent); + mInflatedViewRef = new WeakReference<>(view); if (mInflateListener != null) { mInflateListener.onInflate(this, view); } @@ -317,4 +345,18 @@ public final class ViewStub extends View { */ void onInflate(ViewStub stub, View inflated); } + + /** @hide **/ + public class ViewReplaceRunnable implements Runnable { + public final View view; + + ViewReplaceRunnable(View view) { + this.view = view; + } + + @Override + public void run() { + replaceSelfWithView(view, (ViewGroup) getParent()); + } + } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 8a9bb33895f4..82379c47a679 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -509,6 +509,11 @@ public interface WindowManagerPolicy { * Notifies window manager that {@link #isShowingDreamLw} has changed. */ void notifyShowingDreamChanged(); + + /** + * Notifies window manager that {@link #isKeyguardTrustedLw} has changed. + */ + void notifyKeyguardTrustedChanged(); } public interface PointerEventListener { @@ -667,7 +672,7 @@ public interface WindowManagerPolicy { * button bar. */ public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, - int uiMode); + int uiMode, int displayId); /** * Return the display height available after excluding any screen @@ -675,7 +680,7 @@ public interface WindowManagerPolicy { * button bar. */ public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, - int uiMode); + int uiMode, int displayId); /** * Return the available screen width that we should report for the @@ -684,7 +689,7 @@ public interface WindowManagerPolicy { * that to account for more transient decoration like a status bar. */ public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, - int uiMode); + int uiMode, int displayId); /** * Return the available screen height that we should report for the @@ -693,7 +698,7 @@ public interface WindowManagerPolicy { * that to account for more transient decoration like a status bar. */ public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, - int uiMode); + int uiMode, int displayId); /** * Return whether the given window can become the Keyguard window. Typically returns true for diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 80380897fd39..2f12e9b5be83 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -34,6 +34,54 @@ import java.util.Arrays; */ public class EditorInfo implements InputType, Parcelable { /** + * Masks for {@link inputType} + * + * <pre> + * |-------|-------|-------|-------| + * 1111 TYPE_MASK_CLASS + * 11111111 TYPE_MASK_VARIATION + * 111111111111 TYPE_MASK_FLAGS + * |-------|-------|-------|-------| + * TYPE_NULL + * |-------|-------|-------|-------| + * 1 TYPE_CLASS_TEXT + * 1 TYPE_TEXT_VARIATION_URI + * 1 TYPE_TEXT_VARIATION_EMAIL_ADDRESS + * 11 TYPE_TEXT_VARIATION_EMAIL_SUBJECT + * 1 TYPE_TEXT_VARIATION_SHORT_MESSAGE + * 1 1 TYPE_TEXT_VARIATION_LONG_MESSAGE + * 11 TYPE_TEXT_VARIATION_PERSON_NAME + * 111 TYPE_TEXT_VARIATION_POSTAL_ADDRESS + * 1 TYPE_TEXT_VARIATION_PASSWORD + * 1 1 TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + * 1 1 TYPE_TEXT_VARIATION_WEB_EDIT_TEXT + * 1 11 TYPE_TEXT_VARIATION_FILTER + * 11 TYPE_TEXT_VARIATION_PHONETIC + * 11 1 TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS + * 111 TYPE_TEXT_VARIATION_WEB_PASSWORD + * 1 TYPE_TEXT_FLAG_CAP_CHARACTERS + * 1 TYPE_TEXT_FLAG_CAP_WORDS + * 1 TYPE_TEXT_FLAG_CAP_SENTENCES + * 1 TYPE_TEXT_FLAG_AUTO_CORRECT + * 1 TYPE_TEXT_FLAG_AUTO_COMPLETE + * 1 TYPE_TEXT_FLAG_MULTI_LINE + * 1 TYPE_TEXT_FLAG_IME_MULTI_LINE + * 1 TYPE_TEXT_FLAG_NO_SUGGESTIONS + * |-------|-------|-------|-------| + * 1 TYPE_CLASS_NUMBER + * 1 TYPE_NUMBER_VARIATION_PASSWORD + * 1 TYPE_NUMBER_FLAG_SIGNED + * 1 TYPE_NUMBER_FLAG_DECIMAL + * |-------|-------|-------|-------| + * 11 TYPE_CLASS_PHONE + * |-------|-------|-------|-------| + * 1 TYPE_CLASS_DATETIME + * 1 TYPE_DATETIME_VARIATION_DATE + * 1 TYPE_DATETIME_VARIATION_TIME + * |-------|-------|-------|-------|</pre> + */ + + /** * The content type of the text box, whose bits are defined by * {@link InputType}. * @@ -107,6 +155,26 @@ public class EditorInfo implements InputType, Parcelable { public static final int IME_ACTION_PREVIOUS = 0x00000007; /** + * Flag of {@link #imeOptions}: used to request that the IME does not update any personalized + * data such as typing history and personalized language model based on what the user typed on + * this text editing object. Typical use cases are: + * <ul> + * <li>When the application is in a special mode, where user's activities are expected to be + * not recorded in the application's history. Some web browsers and chat applications may + * have this kind of modes.</li> + * <li>When storing typing history does not make much sense. Specifying this flag in typing + * games may help to avoid typing history from being filled up with words that the user is + * less likely to type in their daily life. Another example is that when the application + * already knows that the expected input is not a valid word (e.g. a promotion code that is + * not a valid word in any natural language).</li> + * </ul> + * + * <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may not + * respect it.</p> + */ + public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000; + + /** * Flag of {@link #imeOptions}: used to request that the IME never go * into fullscreen mode. * By default, IMEs may go into full screen mode when they think @@ -208,6 +276,32 @@ public class EditorInfo implements InputType, Parcelable { public static final int IME_NULL = 0x00000000; /** + * Masks for {@link imeOptions} + * + * <pre> + * |-------|-------|-------|-------| + * 1111 IME_MASK_ACTION + * |-------|-------|-------|-------| + * IME_ACTION_UNSPECIFIED + * 1 IME_ACTION_NONE + * 1 IME_ACTION_GO + * 11 IME_ACTION_SEARCH + * 1 IME_ACTION_SEND + * 1 1 IME_ACTION_NEXT + * 11 IME_ACTION_DONE + * 111 IME_ACTION_PREVIOUS + * 1 IME_FLAG_NO_PERSONALIZED_LEARNING + * 1 IME_FLAG_NO_FULLSCREEN + * 1 IME_FLAG_NAVIGATE_PREVIOUS + * 1 IME_FLAG_NAVIGATE_NEXT + * 1 IME_FLAG_NO_EXTRACT_UI + * 1 IME_FLAG_NO_ACCESSORY_ACTION + * 1 IME_FLAG_NO_ENTER_ACTION + * 1 IME_FLAG_FORCE_ASCII + * |-------|-------|-------|-------|</pre> + */ + + /** * Extended type information for the editor, to help the IME better * integrate with it. */ diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java index b39705e0b1fa..7104a2871f21 100644 --- a/core/java/android/view/inputmethod/InputContentInfo.java +++ b/core/java/android/view/inputmethod/InputContentInfo.java @@ -18,11 +18,14 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ClipDescription; +import android.content.ContentProvider; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import android.os.UserHandle; import com.android.internal.inputmethod.IInputContentUriToken; @@ -33,8 +36,24 @@ import java.security.InvalidParameterException; */ public final class InputContentInfo implements Parcelable { + /** + * The content URI that may or may not have a user ID embedded by + * {@link ContentProvider#maybeAddUserId(Uri, int)}. This always preserves the exact value + * specified to a constructor. In other words, if it had user ID embedded when it was passed + * to the constructor, it still has the same user ID no matter if it is valid or not. + */ @NonNull private final Uri mContentUri; + /** + * The user ID to which {@link #mContentUri} belongs to. If {@link #mContentUri} already + * embedded the user ID when it was specified then this fields has the same user ID. Otherwise + * the user ID is determined based on the process ID when the constructor is called. + * + * <p>CAUTION: If you received {@link InputContentInfo} from a different process, there is no + * guarantee that this value is correct and valid. Never use this for any security purpose</p> + */ + @UserIdInt + private final int mContentUriOwnerUserId; @NonNull private final ClipDescription mDescription; @Nullable @@ -73,6 +92,8 @@ public final class InputContentInfo implements Parcelable { @Nullable Uri linkUri) { validateInternal(contentUri, description, linkUri, true /* throwException */); mContentUri = contentUri; + mContentUriOwnerUserId = + ContentProvider.getUserIdFromUri(mContentUri, UserHandle.myUserId()); mDescription = description; mLinkUri = linkUri; } @@ -139,7 +160,14 @@ public final class InputContentInfo implements Parcelable { * @return Content URI with which the content can be obtained. */ @NonNull - public Uri getContentUri() { return mContentUri; } + public Uri getContentUri() { + // Fix up the content URI when and only when the caller's user ID does not match the owner's + // user ID. + if (mContentUriOwnerUserId != UserHandle.myUserId()) { + return ContentProvider.maybeAddUserId(mContentUri, mContentUriOwnerUserId); + } + return mContentUri; + } /** * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()} @@ -203,6 +231,7 @@ public final class InputContentInfo implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { Uri.writeToParcel(dest, mContentUri); + dest.writeInt(mContentUriOwnerUserId); mDescription.writeToParcel(dest, flags); Uri.writeToParcel(dest, mLinkUri); if (mUriToken != null) { @@ -215,6 +244,7 @@ public final class InputContentInfo implements Parcelable { private InputContentInfo(@NonNull Parcel source) { mContentUri = Uri.CREATOR.createFromParcel(source); + mContentUriOwnerUserId = source.readInt(); mDescription = ClipDescription.CREATOR.createFromParcel(source); mLinkUri = Uri.CREATOR.createFromParcel(source); if (source.readInt() == 1) { diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index f4ea90b27274..eb0c44c3a07d 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -17,8 +17,8 @@ package android.webkit; import android.annotation.SystemApi; +import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.Application; import android.content.Context; @@ -57,7 +57,9 @@ import java.util.zip.ZipFile; @SystemApi public final class WebViewFactory { - private static final String CHROMIUM_WEBVIEW_FACTORY = + // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote. + /** @hide */ + public static final String CHROMIUM_WEBVIEW_FACTORY = "com.android.webview.chromium.WebViewChromiumFactoryProvider"; private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create"; @@ -292,7 +294,7 @@ public final class WebViewFactory { // killed if the package info goes out-of-date. Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "ActivityManager.addPackageDependency()"); try { - ActivityManagerNative.getDefault().addPackageDependency( + ActivityManager.getService().addPackageDependency( response.packageInfo.packageName); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index bc6e7b4a9dd3..c2069741d6cd 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -16,14 +16,19 @@ package android.webkit; +import android.app.LoadedApk; import android.content.pm.PackageInfo; import android.os.Build; import android.os.SystemService; import android.os.ZygoteProcess; +import android.text.TextUtils; import android.util.Log; +import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeoutException; /** @hide */ @@ -122,11 +127,21 @@ public class WebViewZygote { try { sZygote = new ZygoteProcess("webview_zygote", null); - String packagePath = sPackage.applicationInfo.sourceDir; - String libsPath = sPackage.applicationInfo.nativeLibraryDir; - - Log.d(LOGTAG, "Preloading package " + packagePath + " " + libsPath); - sZygote.preloadPackageForAbi(packagePath, libsPath, Build.SUPPORTED_ABIS[0]); + // All the work below is usually done by LoadedApk, but the zygote can't talk to + // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so + // doesn't have an ActivityThread and can't use Binder. + // Instead, figure out the paths here, in the system server where we have access to + // the package manager. Reuse the logic from LoadedApk to determine the correct + // paths and pass them to the zygote as strings. + final List<String> zipPaths = new ArrayList<>(10); + final List<String> libPaths = new ArrayList<>(10); + LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths); + final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths); + final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) : + TextUtils.join(File.pathSeparator, zipPaths); + + Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath); + sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]); } catch (Exception e) { Log.e(LOGTAG, "Error connecting to " + serviceName, e); sZygote = null; diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 9d228cf667b1..bbc50dafa576 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -312,10 +312,10 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSp } /** - * Control whether methods that change the list ({@link #add}, - * {@link #insert}, {@link #remove}, {@link #clear}) automatically call - * {@link #notifyDataSetChanged}. If set to false, caller must - * manually call notifyDataSetChanged() to have the changes + * Control whether methods that change the list ({@link #add}, {@link #addAll(Collection)}, + * {@link #addAll(Object[])}, {@link #insert}, {@link #remove}, {@link #clear}, + * {@link #sort(Comparator)}) automatically call {@link #notifyDataSetChanged}. If set to + * false, caller must manually call notifyDataSetChanged() to have the changes * reflected in the attached view. * * The default is true, and calling notifyDataSetChanged() 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/RemoteViews.java b/core/java/android/widget/RemoteViews.java index b2a77d0051b3..a9268d4e3dd9 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -58,6 +58,7 @@ import android.view.RemotableViewMethod; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.ViewStub; import android.widget.AdapterView.OnItemClickListener; import com.android.internal.R; @@ -403,6 +404,7 @@ public class RemoteViews implements Parcelable, Filter { // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache mBitmapCache = new BitmapCache(); setBitmapCache(mBitmapCache); + recalculateMemoryUsage(); } private class SetEmptyView extends Action { @@ -1456,6 +1458,13 @@ public class RemoteViews implements Parcelable, Filter { if (endAction == null) { return ACTION_NOOP; } else { + // Special case view stub + if (endAction instanceof ViewStub.ViewReplaceRunnable) { + root.createTree(); + // Replace child tree + root.findViewTreeById(viewId).replaceView( + ((ViewStub.ViewReplaceRunnable) endAction).view); + } return new RunnableAction(endAction); } } @@ -1581,16 +1590,26 @@ public class RemoteViews implements Parcelable, Filter { if ((target == null) || !(target.mRoot instanceof ViewGroup)) { return ACTION_NOOP; } + final ViewGroup targetVg = (ViewGroup) target.mRoot; if (nestedViews == null) { // Clear all children when nested views omitted target.mChildren = null; - return this; + return new RuntimeAction() { + @Override + public void apply(View root, ViewGroup rootParent, OnClickHandler handler) + throws ActionException { + targetVg.removeAllViews(); + } + }; } else { // Inflate nested views and perform all the async tasks for the child remoteView. final Context context = root.mRoot.getContext(); final AsyncApplyTask task = nestedViews.getAsyncApplyTask( - context, (ViewGroup) target.mRoot, null, handler); + context, targetVg, null, handler); final ViewTree tree = task.doInBackground(); + if (tree == null) { + throw new ActionException(task.mError); + } // Update the global view tree, so that next call to findViewTreeById // goes through the subtree as well. @@ -1600,10 +1619,8 @@ public class RemoteViews implements Parcelable, Filter { @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException { - // This view will exist as we have already made sure - final ViewGroup target = (ViewGroup) root.findViewById(viewId); task.onPostExecute(tree); - target.addView(task.mResult); + targetVg.addView(task.mResult); } }; } @@ -2101,26 +2118,8 @@ public class RemoteViews implements Parcelable, Filter { return mMemoryUsage; } - @SuppressWarnings("deprecation") public void addBitmapMemory(Bitmap b) { - final Bitmap.Config c = b.getConfig(); - // If we don't know, be pessimistic and assume 4 - int bpp = 4; - if (c != null) { - switch (c) { - case ALPHA_8: - bpp = 1; - break; - case RGB_565: - case ARGB_4444: - bpp = 2; - break; - case ARGB_8888: - bpp = 4; - break; - } - } - increment(b.getWidth() * b.getHeight() * bpp); + increment(b.getAllocationByteCount()); } int mMemoryUsage; @@ -3360,7 +3359,7 @@ public class RemoteViews implements Parcelable, Filter { int count = mRV.mActions.size(); mActions = new Action[count]; for (int i = 0; i < count && !isCancelled(); i++) { - // TODO: check if isCanclled in nested views. + // TODO: check if isCancelled in nested views. mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler); } } else { @@ -3629,7 +3628,7 @@ public class RemoteViews implements Parcelable, Filter { * and can be searched. */ private static class ViewTree { - private final View mRoot; + private View mRoot; private ArrayList<ViewTree> mChildren; @@ -3643,7 +3642,7 @@ public class RemoteViews implements Parcelable, Filter { } mChildren = new ArrayList<>(); - if (mRoot instanceof ViewGroup && mRoot.isRootNamespace()) { + if (mRoot instanceof ViewGroup) { ViewGroup vg = (ViewGroup) mRoot; int count = vg.getChildCount(); for (int i = 0; i < count; i++) { @@ -3668,6 +3667,12 @@ public class RemoteViews implements Parcelable, Filter { return null; } + public void replaceView(View v) { + mRoot = v; + mChildren = null; + createTree(); + } + public View findViewById(int id) { if (mChildren == null) { return mRoot.findViewById(id); @@ -3685,6 +3690,12 @@ public class RemoteViews implements Parcelable, Filter { } private void addViewChild(View v) { + // ViewTree only contains Views which can be found using findViewById. + // If isRootNamespace is true, this view is skipped. + // @see ViewGroup#findViewTraversal(int) + if (v.isRootNamespace()) { + return; + } final ViewTree target; // If the view has a valid id, i.e., if can be found using findViewById, add it to the @@ -3697,7 +3708,7 @@ public class RemoteViews implements Parcelable, Filter { target = this; } - if (v instanceof ViewGroup && v.isRootNamespace()) { + if (v instanceof ViewGroup) { if (target.mChildren == null) { target.mChildren = new ArrayList<>(); ViewGroup vg = (ViewGroup) v; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9c48cf8e8806..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; @@ -1683,12 +1685,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Return the text the TextView is displaying. If setText() was called with - * an argument of BufferType.SPANNABLE or BufferType.EDITABLE, you can cast + * Return the text that TextView is displaying. If {@link #setText(CharSequence)} was called + * with an argument of {@link android.widget.TextView.BufferType#SPANNABLE BufferType.SPANNABLE} + * or {@link android.widget.TextView.BufferType#EDITABLE BufferType.EDITABLE}, you can cast * the return value from this method to Spannable or Editable, respectively. - * - * Note: The content of the return value should not be modified. If you want - * a modifiable one, you should make your own copy first. + * <p/> + * The content of the return value should not be modified. If you want a modifiable one, you + * should make your own copy first. * * @attr ref android.R.styleable#TextView_text */ @@ -1705,8 +1708,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Return the text the TextView is displaying as an Editable object. If - * the text is not editable, null is returned. + * Return the text that TextView is displaying as an Editable object. If the text is not + * editable, null is returned. * * @see #getText */ @@ -4148,18 +4151,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Convenience method: Append the specified text to the TextView's - * display buffer, upgrading it to BufferType.EDITABLE if it was - * not already editable. + * Convenience method to append the specified text to the TextView's + * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE} + * if it was not already editable. + * + * @param text text to be appended to the already displayed text */ public final void append(CharSequence text) { append(text, 0, text.length()); } /** - * Convenience method: Append the specified text slice to the TextView's - * display buffer, upgrading it to BufferType.EDITABLE if it was - * not already editable. + * Convenience method to append the specified text slice to the TextView's + * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE} + * if it was not already editable. + * + * @param text text to be appended to the already displayed text + * @param start the index of the first character in the {@code text} + * @param end the index of the character following the last character in the {@code text} + * + * @see Appendable#append(CharSequence, int, int) */ public void append(CharSequence text, int start, int end) { if (!(mText instanceof Editable)) { @@ -4403,7 +4414,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /////////////////////////////////////////////////////////////////////////// /** - * Sets the Factory used to create new Editables. + * Sets the Factory used to create new {@link Editable Editables}. + * + * @param factory {@link android.text.Editable.Factory Editable.Factory} to be used + * + * @see android.text.Editable.Factory + * @see android.widget.TextView.BufferType#EDITABLE */ public final void setEditableFactory(Editable.Factory factory) { mEditableFactory = factory; @@ -4411,7 +4427,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Sets the Factory used to create new Spannables. + * Sets the Factory used to create new {@link Spannable Spannables}. + * + * @param factory {@link android.text.Spannable.Factory Spannable.Factory} to be used + * + * @see android.text.Spannable.Factory + * @see android.widget.TextView.BufferType#SPANNABLE */ public final void setSpannableFactory(Spannable.Factory factory) { mSpannableFactory = factory; @@ -4419,13 +4440,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Sets the string value of the TextView. TextView <em>does not</em> accept + * Sets the text to be displayed. TextView <em>does not</em> accept * HTML-like formatting, which you can do with text strings in XML resource files. * To style your strings, attach android.text.style.* objects to a - * {@link android.text.SpannableString SpannableString}, or see the + * {@link android.text.SpannableString}, or see the * <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources"> * Available Resource Types</a> documentation for an example of setting * formatted text in the XML resource file. + * <p/> + * When required, TextView will use {@link android.text.Spannable.Factory} to create final or + * intermediate {@link Spannable Spannables}. Likewise it will use + * {@link android.text.Editable.Factory} to create final or intermediate + * {@link Editable Editables}. + * + * @param text text to be displayed * * @attr ref android.R.styleable#TextView_text */ @@ -4435,10 +4463,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Like {@link #setText(CharSequence)}, - * except that the cursor position (if any) is retained in the new text. + * Sets the text to be displayed but retains the cursor position. Same as + * {@link #setText(CharSequence)} except that the cursor position (if any) is retained in the + * new text. + * <p/> + * When required, TextView will use {@link android.text.Spannable.Factory} to create final or + * intermediate {@link Spannable Spannables}. Likewise it will use + * {@link android.text.Editable.Factory} to create final or intermediate + * {@link Editable Editables}. * - * @param text The new text to place in the text view. + * @param text text to be displayed * * @see #setText(CharSequence) */ @@ -4448,9 +4482,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Sets the text that this TextView is to display (see - * {@link #setText(CharSequence)}) and also sets whether it is stored - * in a styleable/spannable buffer and whether it is editable. + * Sets the text to be displayed and the {@link android.widget.TextView.BufferType}. + * <p/> + * When required, TextView will use {@link android.text.Spannable.Factory} to create final or + * intermediate {@link Spannable Spannables}. Likewise it will use + * {@link android.text.Editable.Factory} to create final or intermediate + * {@link Editable Editables}. + * + * @param text text to be displayed + * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is + * stored as a static text, styleable/spannable text, or editable text + * + * @see #setText(CharSequence) + * @see android.widget.TextView.BufferType + * @see #setSpannableFactory(Spannable.Factory) + * @see #setEditableFactory(Editable.Factory) * * @attr ref android.R.styleable#TextView_text * @attr ref android.R.styleable#TextView_bufferType @@ -4617,10 +4663,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Sets the TextView to display the specified slice of the specified - * char array. You must promise that you will not change the contents + * char array. You must promise that you will not change the contents * of the array except for right before another call to setText(), * since the TextView has no way to know that the text * has changed and that it needs to invalidate and re-layout. + * + * @param text char array to be displayed + * @param start start index in the char array + * @param len length of char count after {@code start} */ public final void setText(char[] text, int start, int len) { int oldlen = 0; @@ -4651,8 +4701,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Like {@link #setText(CharSequence, android.widget.TextView.BufferType)}, - * except that the cursor position (if any) is retained in the new text. + * Sets the text to be displayed and the {@link android.widget.TextView.BufferType} but retains + * the cursor position. Same as + * {@link #setText(CharSequence, android.widget.TextView.BufferType)} except that the cursor + * position (if any) is retained in the new text. + * <p/> + * When required, TextView will use {@link android.text.Spannable.Factory} to create final or + * intermediate {@link Spannable Spannables}. Likewise it will use + * {@link android.text.Editable.Factory} to create final or intermediate + * {@link Editable Editables}. + * + * @param text text to be displayed + * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is + * stored as a static text, styleable/spannable text, or editable text * * @see #setText(CharSequence, android.widget.TextView.BufferType) */ @@ -4672,11 +4733,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * Sets the text to be displayed using a string resource identifier. + * + * @param resid the resource identifier of the string resource to be displayed + * + * @see #setText(CharSequence) + * + * @attr ref android.R.styleable#TextView_text + */ @android.view.RemotableViewMethod public final void setText(@StringRes int resid) { setText(getContext().getResources().getText(resid)); } + /** + * Sets the text to be displayed using a string resource identifier and the + * {@link android.widget.TextView.BufferType}. + * <p/> + * When required, TextView will use {@link android.text.Spannable.Factory} to create final or + * intermediate {@link Spannable Spannables}. Likewise it will use + * {@link android.text.Editable.Factory} to create final or intermediate + * {@link Editable Editables}. + * + * @param resid the resource identifier of the string resource to be displayed + * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is + * stored as a static text, styleable/spannable text, or editable text + * + * @see #setText(int) + * @see #setText(CharSequence) + * @see android.widget.TextView.BufferType + * @see #setSpannableFactory(Spannable.Factory) + * @see #setEditableFactory(Editable.Factory) + * + * @attr ref android.R.styleable#TextView_text + * @attr ref android.R.styleable#TextView_bufferType + */ public final void setText(@StringRes int resid, BufferType type) { setText(getContext().getResources().getText(resid), type); } @@ -5110,7 +5202,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Set the extra input data of the text, which is the * {@link EditorInfo#extras TextBoxAttribute.extras} * Bundle that will be filled in when creating an input connection. The - * given integer is the resource ID of an XML resource holding an + * given integer is the resource identifier of an XML resource holding an * {@link android.R.styleable#InputExtras <input-extras>} XML tree. * * @see #getInputExtras(boolean) @@ -5157,7 +5249,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * call {@link InputMethodManager#restartInput(View)}.</p> * @param hintLocales List of the languages that the user is supposed to switch to no matter * what input method subtype is currently used. Set {@code null} to clear the current "hint". - * @see #getImeHIntLocales() + * @see #getImeHintLocales() * @see android.view.inputmethod.EditorInfo#hintLocales */ public void setImeHintLocales(@Nullable LocaleList hintLocales) { @@ -7000,11 +7092,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) - .setHyphenationFrequency(mHyphenationFrequency); + .setHyphenationFrequency(mHyphenationFrequency) + .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); if (shouldEllipsize) { builder.setEllipsize(mEllipsize) - .setEllipsizedWidth(ellipsisWidth) - .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + .setEllipsizedWidth(ellipsisWidth); } mHintLayout = builder.build(); } @@ -7091,11 +7183,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) - .setHyphenationFrequency(mHyphenationFrequency); + .setHyphenationFrequency(mHyphenationFrequency) + .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); if (shouldEllipsize) { builder.setEllipsize(effectiveEllipsize) - .setEllipsizedWidth(ellipsisWidth) - .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); + .setEllipsizedWidth(ellipsisWidth); } // TODO: explore always setting maxLines result = builder.build(); @@ -7367,9 +7459,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return 0; } - int linecount = layout.getLineCount(); - int pad = getCompoundPaddingTop() + getCompoundPaddingBottom(); - int desired = layout.getLineTop(linecount); + /* + * Don't cap the hint to a certain number of lines. + * (Do cap it, though, if we have a maximum pixel height.) + */ + int desired = layout.getHeight(cap); final Drawables dr = mDrawables; if (dr != null) { @@ -7377,31 +7471,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener desired = Math.max(desired, dr.mDrawableHeightRight); } - desired += pad; - - if (mMaxMode == LINES) { - /* - * Don't cap the hint to a certain number of lines. - * (Do cap it, though, if we have a maximum pixel height.) - */ - if (cap) { - if (linecount > mMaximum) { - desired = layout.getLineTop(mMaximum); - - if (dr != null) { - desired = Math.max(desired, dr.mDrawableHeightLeft); - desired = Math.max(desired, dr.mDrawableHeightRight); - } + desired += getCompoundPaddingTop() + getCompoundPaddingBottom(); - desired += pad; - linecount = mMaximum; - } - } - } else { + if (mMaxMode != LINES) { desired = Math.min(desired, mMaximum); } if (mMinMode == LINES) { + int linecount = layout.getLineCount(); if (linecount < mMinimum) { desired += getLineHeight() * (mMinimum - linecount); } @@ -8847,8 +8924,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * Type of the text buffer that defines the characteristics of the text such as static, + * styleable, or editable. + */ public enum BufferType { - NORMAL, SPANNABLE, EDITABLE, + NORMAL, SPANNABLE, EDITABLE } /** @@ -9606,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/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 3b6073a6eacc..d8f7907524ee 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -70,7 +70,7 @@ import android.widget.ListView; import com.android.internal.R; import com.android.internal.app.ResolverActivity.TargetInfo; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.google.android.collect.Lists; import java.io.File; diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java index 83ad9dc661f2..459071b5dc15 100644 --- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java +++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java @@ -19,7 +19,7 @@ package com.android.internal.app; import com.android.internal.R; import android.app.Activity; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; @@ -122,7 +122,7 @@ public class HeavyWeightSwitcherActivity extends Activity { private OnClickListener mSwitchOldListener = new OnClickListener() { public void onClick(View v) { try { - ActivityManagerNative.getDefault().moveTaskToFront(mCurTask, 0, null); + ActivityManager.getService().moveTaskToFront(mCurTask, 0, null); } catch (RemoteException e) { } finish(); @@ -132,7 +132,7 @@ public class HeavyWeightSwitcherActivity extends Activity { private OnClickListener mSwitchNewListener = new OnClickListener() { public void onClick(View v) { try { - ActivityManagerNative.getDefault().finishHeavyWeightApp(); + ActivityManager.getService().finishHeavyWeightApp(); } catch (RemoteException e) { } try { diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 015e60dd2a7d..0b27c60d3480 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -19,7 +19,7 @@ package com.android.internal.app; import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; import android.app.Activity; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; @@ -110,9 +110,9 @@ public class IntentForwarderActivity extends Activity { int launchedFromUid = -1; String launchedFromPackage = "?"; try { - launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid( + launchedFromUid = ActivityManager.getService().getLaunchedFromUid( getActivityToken()); - launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( + launchedFromPackage = ActivityManager.getService().getLaunchedFromPackage( getActivityToken()); } catch (RemoteException ignored) { } diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java index 472f583fa075..9936ed5c6491 100644 --- a/core/java/com/android/internal/app/LocalePicker.java +++ b/core/java/com/android/internal/app/LocalePicker.java @@ -18,7 +18,7 @@ package com.android.internal.app; import com.android.internal.R; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.app.ListFragment; import android.app.backup.BackupManager; @@ -269,7 +269,7 @@ public class LocalePicker extends ListFragment { */ public static void updateLocales(LocaleList locales) { try { - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); final Configuration config = am.getConfiguration(); config.setLocales(locales); @@ -290,7 +290,7 @@ public class LocalePicker extends ListFragment { */ public static LocaleList getLocales() { try { - return ActivityManagerNative.getDefault() + return ActivityManager.getService() .getConfiguration().getLocales(); } catch (RemoteException e) { // If something went wrong diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 1e26c92dd764..dd8ef180e19c 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -35,7 +35,6 @@ import com.android.internal.R; import com.android.internal.content.PackageMonitor; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.content.ComponentName; import android.content.Context; @@ -71,7 +70,7 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.widget.ResolverDrawerLayout; import java.util.ArrayList; @@ -245,7 +244,7 @@ public class ResolverActivity extends Activity { setProfileSwitchMessageId(intent.getContentUserHint()); try { - mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid( + mLaunchedFromUid = ActivityManager.getService().getLaunchedFromUid( getActivityToken()); } catch (RemoteException e) { mLaunchedFromUid = -1; @@ -864,7 +863,7 @@ public class ResolverActivity extends Activity { } catch (RuntimeException e) { String launchedFromPackage; try { - launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( + launchedFromPackage = ActivityManager.getService().getLaunchedFromPackage( getActivityToken()); } catch (RemoteException e2) { launchedFromPackage = "??"; diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 4e3c3fc94a43..a3134b3bc29b 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -29,7 +29,7 @@ import android.os.FileUtils; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; import android.os.storage.StorageVolume; @@ -53,7 +53,7 @@ import java.util.zip.ZipOutputStream; /** * Constants used internally between the PackageManager * and media container service transports. - * Some utility methods to invoke MountService api. + * Some utility methods to invoke StorageManagerService api. */ public class PackageHelper { public static final int RECOMMEND_INSTALL_INTERNAL = 1; @@ -74,13 +74,13 @@ public class PackageHelper { public static final int APP_INSTALL_INTERNAL = 1; public static final int APP_INSTALL_EXTERNAL = 2; - public static IMountService getMountService() throws RemoteException { + public static IStorageManager getStorageManager() throws RemoteException { IBinder service = ServiceManager.getService("mount"); if (service != null) { - return IMountService.Stub.asInterface(service); + return IStorageManager.Stub.asInterface(service); } else { - Log.e(TAG, "Can't get mount service"); - throw new RemoteException("Could not contact mount service"); + Log.e(TAG, "Can't get storagemanager service"); + throw new RemoteException("Could not contact storagemanager service"); } } @@ -89,23 +89,23 @@ public class PackageHelper { // Round up to nearest MB, plus another MB for filesystem overhead final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1; try { - IMountService mountService = getMountService(); + IStorageManager storageManager = getStorageManager(); if (localLOGV) Log.i(TAG, "Size of container " + sizeMb + " MB"); - int rc = mountService.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid, + int rc = storageManager.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid, isExternal); if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to create secure container " + cid); return null; } - String cachePath = mountService.getSecureContainerPath(cid); + String cachePath = storageManager.getSecureContainerPath(cid); if (localLOGV) Log.i(TAG, "Created secure container " + cid + " at " + cachePath); return cachePath; } catch (RemoteException e) { - Log.e(TAG, "MountService running?"); + Log.e(TAG, "StorageManagerService running?"); } return null; } @@ -114,13 +114,13 @@ public class PackageHelper { // Round up to nearest MB, plus another MB for filesystem overhead final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1; try { - IMountService mountService = getMountService(); - int rc = mountService.resizeSecureContainer(cid, sizeMb, sdEncKey); + IStorageManager storageManager = getStorageManager(); + int rc = storageManager.resizeSecureContainer(cid, sizeMb, sdEncKey); if (rc == StorageResultCode.OperationSucceeded) { return true; } } catch (RemoteException e) { - Log.e(TAG, "MountService running?"); + Log.e(TAG, "StorageManagerService running?"); } Log.e(TAG, "Failed to create secure container " + cid); return false; @@ -132,35 +132,35 @@ public class PackageHelper { public static String mountSdDir(String cid, String key, int ownerUid, boolean readOnly) { try { - int rc = getMountService().mountSecureContainer(cid, key, ownerUid, readOnly); + int rc = getStorageManager().mountSecureContainer(cid, key, ownerUid, readOnly); if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc); return null; } - return getMountService().getSecureContainerPath(cid); + return getStorageManager().getSecureContainerPath(cid); } catch (RemoteException e) { - Log.e(TAG, "MountService running?"); + Log.e(TAG, "StorageManagerService running?"); } return null; } public static boolean unMountSdDir(String cid) { try { - int rc = getMountService().unmountSecureContainer(cid, true); + int rc = getStorageManager().unmountSecureContainer(cid, true); if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc); return false; } return true; } catch (RemoteException e) { - Log.e(TAG, "MountService running?"); + Log.e(TAG, "StorageManagerService running?"); } return false; } public static boolean renameSdDir(String oldId, String newId) { try { - int rc = getMountService().renameSecureContainer(oldId, newId); + int rc = getStorageManager().renameSecureContainer(oldId, newId); if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to rename " + oldId + " to " + newId + "with rc " + rc); @@ -176,7 +176,7 @@ public class PackageHelper { public static String getSdDir(String cid) { try { - return getMountService().getSecureContainerPath(cid); + return getStorageManager().getSecureContainerPath(cid); } catch (RemoteException e) { Log.e(TAG, "Failed to get container path for " + cid + " with exception " + e); @@ -186,7 +186,7 @@ public class PackageHelper { public static String getSdFilesystem(String cid) { try { - return getMountService().getSecureContainerFilesystemPath(cid); + return getStorageManager().getSecureContainerFilesystemPath(cid); } catch (RemoteException e) { Log.e(TAG, "Failed to get container path for " + cid + " with exception " + e); @@ -196,7 +196,7 @@ public class PackageHelper { public static boolean finalizeSdDir(String cid) { try { - int rc = getMountService().finalizeSecureContainer(cid); + int rc = getStorageManager().finalizeSecureContainer(cid); if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to finalize container " + cid); return false; @@ -212,7 +212,7 @@ public class PackageHelper { public static boolean destroySdDir(String cid) { try { if (localLOGV) Log.i(TAG, "Forcibly destroying container " + cid); - int rc = getMountService().destroySecureContainer(cid, true); + int rc = getStorageManager().destroySecureContainer(cid, true); if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to destroy container " + cid); return false; @@ -227,7 +227,7 @@ public class PackageHelper { public static String[] getSecureContainerList() { try { - return getMountService().getSecureContainerList(); + return getStorageManager().getSecureContainerList(); } catch (RemoteException e) { Log.e(TAG, "Failed to get secure container list with exception" + e); @@ -237,7 +237,7 @@ public class PackageHelper { public static boolean isContainerMounted(String cid) { try { - return getMountService().isSecureContainerMounted(cid); + return getStorageManager().isSecureContainerMounted(cid); } catch (RemoteException e) { Log.e(TAG, "Failed to find out if container " + cid + " mounted"); } @@ -325,7 +325,7 @@ public class PackageHelper { public static boolean fixSdPermissions(String cid, int gid, String filename) { try { - int rc = getMountService().fixPermissionsSecureContainer(cid, gid, filename); + int rc = getStorageManager().fixPermissionsSecureContainer(cid, gid, filename); if (rc != StorageResultCode.OperationSucceeded) { Log.i(TAG, "Failed to fixperms container " + cid); return false; diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index ef725da1e463..a94f30867e40 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -19,7 +19,7 @@ import android.content.Context; import android.os.Build; import android.view.View; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; /** * Log all the things. diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java new file mode 100644 index 000000000000..b392186ccc77 --- /dev/null +++ b/core/java/com/android/internal/os/AppFuseMount.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; +import java.io.File; + +public class AppFuseMount implements Parcelable { + final public File mountPoint; + final public ParcelFileDescriptor fd; + + public AppFuseMount(File mountPoint, ParcelFileDescriptor fd) { + this.mountPoint = mountPoint; + this.fd = fd; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.mountPoint.getPath()); + dest.writeParcelable(fd, flags); + } + + public static final Parcelable.Creator<AppFuseMount> CREATOR = + new Parcelable.Creator<AppFuseMount>() { + @Override + public AppFuseMount createFromParcel(Parcel in) { + return new AppFuseMount(new File(in.readString()), in.readParcelable(null)); + } + + @Override + public AppFuseMount[] newArray(int size) { + return new AppFuseMount[size]; + } + }; +} diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java index 80c55fb57186..759148817161 100644 --- a/core/java/com/android/internal/os/RoSystemProperties.java +++ b/core/java/com/android/internal/os/RoSystemProperties.java @@ -27,6 +27,8 @@ public class RoSystemProperties { SystemProperties.getInt("ro.debuggable", 0) == 1; public static final int FACTORYTEST = SystemProperties.getInt("ro.factorytest", 0); + public static final boolean CONTROL_PRIVAPP_PERMISSIONS = + SystemProperties.getBoolean("ro.control_privapp_permissions", false); // ------ ro.config.* -------- // public static final boolean CONFIG_LOW_RAM = diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index e57a224d1440..304c31d54776 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ApplicationErrorReport; import android.os.Build; @@ -113,7 +113,7 @@ public class RuntimeInit { } // Bring up crash dialog, wait for it to be dismissed - ActivityManagerNative.getDefault().handleApplicationCrash( + ActivityManager.getService().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e)); } catch (Throwable t2) { if (t2 instanceof DeadObjectException) { @@ -379,7 +379,7 @@ public class RuntimeInit { */ public static void wtf(String tag, Throwable t, boolean system) { try { - if (ActivityManagerNative.getDefault().handleApplicationWtf( + if (ActivityManager.getService().handleApplicationWtf( mApplicationObject, tag, system, new ApplicationErrorReport.ParcelableCrashInfo(t))) { // The Activity Manager has already written us off -- now exit. diff --git a/core/java/com/android/internal/os/TransferPipe.java b/core/java/com/android/internal/os/TransferPipe.java index e76b395e9e2d..f9041507ffdd 100644 --- a/core/java/com/android/internal/os/TransferPipe.java +++ b/core/java/com/android/internal/os/TransferPipe.java @@ -16,6 +16,7 @@ package com.android.internal.os; +import java.io.Closeable; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -32,13 +33,13 @@ import android.util.Slog; /** * Helper for transferring data through a pipe from a client app. */ -public final class TransferPipe implements Runnable { +public final class TransferPipe implements Runnable, Closeable { static final String TAG = "TransferPipe"; static final boolean DEBUG = false; static final long DEFAULT_TIMEOUT = 5000; // 5 seconds - final Thread mThread;; + final Thread mThread; final ParcelFileDescriptor[] mFds; FileDescriptor mOutFd; @@ -54,8 +55,13 @@ public final class TransferPipe implements Runnable { } public TransferPipe() throws IOException { + this(null); + } + + public TransferPipe(String bufferPrefix) throws IOException { mThread = new Thread(this, "TransferPipe"); mFds = ParcelFileDescriptor.createPipe(); + mBufferPrefix = bufferPrefix; } ParcelFileDescriptor getReadFd() { @@ -70,6 +76,11 @@ public final class TransferPipe implements Runnable { mBufferPrefix = prefix; } + public static void dumpAsync(IBinder binder, FileDescriptor out, String[] args) + throws IOException, RemoteException { + goDump(binder, out, args); + } + static void go(Caller caller, IInterface iface, FileDescriptor out, String prefix, String[] args) throws IOException, RemoteException { go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT); @@ -86,12 +97,9 @@ public final class TransferPipe implements Runnable { return; } - TransferPipe tp = new TransferPipe(); - try { + try (TransferPipe tp = new TransferPipe()) { caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args); tp.go(out, timeout); - } finally { - tp.kill(); } } @@ -111,12 +119,9 @@ public final class TransferPipe implements Runnable { return; } - TransferPipe tp = new TransferPipe(); - try { + try (TransferPipe tp = new TransferPipe()) { binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args); tp.go(out, timeout); - } finally { - tp.kill(); } } @@ -173,6 +178,11 @@ public final class TransferPipe implements Runnable { } } + @Override + public void close() { + kill(); + } + public void kill() { synchronized (this) { closeFd(0); diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index 11dd0e8771a7..d968e3c939ab 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -16,14 +16,17 @@ package com.android.internal.os; +import android.app.ApplicationLoaders; import android.net.LocalSocket; import android.os.Build; import android.system.ErrnoException; import android.system.Os; import android.text.TextUtils; import android.util.Log; +import android.webkit.WebViewFactory; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; /** * Startup class for the WebView zygote process. @@ -52,7 +55,27 @@ class WebViewZygoteInit { @Override protected boolean handlePreloadPackage(String packagePath, String libsPath) { - // TODO: Use preload information to setup the ClassLoader. + // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that + // our children will reuse the same classloader instead of creating their own. + // This enables us to preload Java and native code in the webview zygote process and + // have the preloaded versions actually be used post-fork. + ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader( + packagePath, libsPath); + + // Once we have the classloader, look up the WebViewFactoryProvider implementation and + // call preloadInZygote() on it to give it the opportunity to preload the native library + // and perform any other initialisation work that should be shared among the children. + try { + Class providerClass = Class.forName(WebViewFactory.CHROMIUM_WEBVIEW_FACTORY, true, + loader); + Object result = providerClass.getMethod("preloadInZygote").invoke(null); + if (!((Boolean)result).booleanValue()) { + Log.e(TAG, "preloadInZygote returned false"); + } + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | + IllegalAccessException | InvocationTargetException e) { + Log.e(TAG, "Exception while preloading package", e); + } return false; } } diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 594b6ab72ef3..c03bcdf3a834 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -17,6 +17,8 @@ package com.android.internal.os; import android.os.Process; +import android.os.Trace; +import android.util.BootTimingsTraceLog; import android.util.Slog; import dalvik.system.VMRuntime; @@ -75,7 +77,8 @@ public class WrapperInit { } // Mimic system Zygote preloading. - ZygoteInit.preload(); + ZygoteInit.preload(new BootTimingsTraceLog("WrapperInitTiming", + Trace.TRACE_TAG_DALVIK)); // Launch the application. String[] runtimeArgs = new String[args.length - 2]; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index e1118d84ed7b..cdd267e8184f 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -36,11 +36,13 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.text.Hyphenator; +import android.util.BootTimingsTraceLog; import android.util.EventLog; import android.util.Log; import android.webkit.WebViewFactory; import android.widget.TextView; +import com.android.internal.logging.MetricsLogger; import com.android.internal.os.InstallerConnection.InstallerException; import dalvik.system.DexFile; @@ -106,20 +108,20 @@ public class ZygoteInit { private static final int ROOT_UID = 0; private static final int ROOT_GID = 0; - static void preload() { + static void preload(BootTimingsTraceLog bootTimingsTraceLog) { Log.d(TAG, "begin preload"); - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "BeginIcuCachePinning"); + bootTimingsTraceLog.traceBegin("BeginIcuCachePinning"); beginIcuCachePinning(); - Trace.traceEnd(Trace.TRACE_TAG_DALVIK); - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses"); + bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning + bootTimingsTraceLog.traceBegin("PreloadClasses"); preloadClasses(); - Trace.traceEnd(Trace.TRACE_TAG_DALVIK); - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources"); + bootTimingsTraceLog.traceEnd(); // PreloadClasses + bootTimingsTraceLog.traceBegin("PreloadResources"); preloadResources(); - Trace.traceEnd(Trace.TRACE_TAG_DALVIK); - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL"); + bootTimingsTraceLog.traceEnd(); // PreloadResources + bootTimingsTraceLog.traceBegin("PreloadOpenGL"); preloadOpenGL(); - Trace.traceEnd(Trace.TRACE_TAG_DALVIK); + bootTimingsTraceLog.traceEnd(); // PreloadOpenGL preloadSharedLibraries(); preloadTextResources(); // Ask the WebViewFactory to do any initialization that must run in the zygote process, @@ -639,7 +641,13 @@ public class ZygoteInit { } try { - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit"); + // Report Zygote start time to tron + MetricsLogger.histogram(null, "boot_zygote_init", (int) SystemClock.uptimeMillis()); + + String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; + BootTimingsTraceLog bootTimingsTraceLog = new BootTimingsTraceLog(bootTimeTag, + Trace.TRACE_TAG_DALVIK); + bootTimingsTraceLog.traceBegin("ZygoteInit"); RuntimeInit.enableDdms(); // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); @@ -664,22 +672,23 @@ public class ZygoteInit { } zygoteServer.registerServerSocket(socketName); - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload"); + bootTimingsTraceLog.traceBegin("ZygotePreload"); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); - preload(); + preload(bootTimingsTraceLog); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); - Trace.traceEnd(Trace.TRACE_TAG_DALVIK); + bootTimingsTraceLog.traceEnd(); // ZygotePreload // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup - Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC"); + bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); - Trace.traceEnd(Trace.TRACE_TAG_DALVIK); + bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC + bootTimingsTraceLog.traceEnd(); // ZygoteInit // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java index bed7c1ba4ed3..eb75bd497434 100644 --- a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java +++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; +import android.os.UserHandle; import android.provider.Settings; /** @@ -72,7 +73,7 @@ public class EmergencyAffordanceManager { Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY); intent.setData(getPhoneUri(context)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + context.startActivityAsUser(intent, UserHandle.CURRENT); } /** diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 878f3a69a504..2a004cfb2d40 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -21,7 +21,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.*; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.SearchManager; import android.os.UserHandle; @@ -540,6 +540,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WindowManager.LayoutParams params = getAttributes(); if (!TextUtils.equals(title, params.accessibilityTitle)) { params.accessibilityTitle = TextUtils.stringOrSpannedString(title); + if (mDecor != null) { + // ViewRootImpl will make sure the change propagates to WindowManagerService + ViewRootImpl vr = mDecor.getViewRootImpl(); + if (vr != null) { + vr.onWindowTitleChanged(); + } + } dispatchWindowAttributesChanged(getAttributes()); } } @@ -3708,9 +3715,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } public static void sendCloseSystemWindows(Context context, String reason) { - if (ActivityManagerNative.isSystemReady()) { + if (ActivityManager.isSystemReady()) { try { - ActivityManagerNative.getDefault().closeSystemDialogs(reason); + ActivityManager.getService().closeSystemDialogs(reason); } catch (RemoteException e) { } } diff --git a/core/java/com/android/internal/policy/PipMotionHelper.java b/core/java/com/android/internal/policy/PipMotionHelper.java index 05434423e9c2..944cd323b295 100644 --- a/core/java/com/android/internal/policy/PipMotionHelper.java +++ b/core/java/com/android/internal/policy/PipMotionHelper.java @@ -18,7 +18,7 @@ package com.android.internal.policy; import android.animation.RectEvaluator; import android.animation.ValueAnimator; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.graphics.Rect; import android.os.Handler; @@ -51,7 +51,7 @@ public class PipMotionHelper { public void resizeToBounds(Rect toBounds) { mHandler.post(() -> { if (mActivityManager == null) { - mActivityManager = ActivityManagerNative.getDefault(); + mActivityManager = ActivityManager.getService(); } try { mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */); diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java index cbacf269a0f0..62d506f78157 100644 --- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java @@ -41,8 +41,12 @@ public class PipSnapAlgorithm { // Allows snapping to anywhere along the edge of the screen private static final int SNAP_MODE_EDGE = 2; + // The friction multiplier to control how slippery the PIP is when flung private static final float SCROLL_FRICTION_MULTIPLIER = 8f; + // The fraction of the stack width to show when minimized + private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f; + private final Context mContext; private final ArrayList<Integer> mSnapGravities = new ArrayList<>(); @@ -122,6 +126,18 @@ public class PipSnapAlgorithm { } /** + * Applies the offset to the {@param stackBounds} to adjust it to a minimized state. + */ + public void applyMinimizedOffset(Rect stackBounds, Rect movementBounds, Point displaySize) { + int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * stackBounds.width()); + if (stackBounds.left <= movementBounds.centerX()) { + stackBounds.offsetTo(-stackBounds.width() + visibleWidth, stackBounds.top); + } else { + stackBounds.offsetTo(displaySize.x - visibleWidth, stackBounds.top); + } + } + + /** * @return returns a fraction that describes where along the {@param movementBounds} the * {@param stackBounds} are. If the {@param stackBounds} are not currently on the * {@param movementBounds} exactly, then they will be snapped to the movement bounds. @@ -208,15 +224,19 @@ public class PipSnapAlgorithm { final int fromTop = Math.abs(stackBounds.top - movementBounds.top); final int fromRight = Math.abs(movementBounds.right - stackBounds.left); final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top); + final int boundedLeft = Math.max(movementBounds.left, Math.min(movementBounds.right, + stackBounds.left)); + final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom, + stackBounds.top)); boundsOut.set(stackBounds); if (fromLeft <= fromTop && fromLeft <= fromRight && fromLeft <= fromBottom) { - boundsOut.offsetTo(movementBounds.left, stackBounds.top); + boundsOut.offsetTo(movementBounds.left, boundedTop); } else if (fromTop <= fromLeft && fromTop <= fromRight && fromTop <= fromBottom) { - boundsOut.offsetTo(stackBounds.left, movementBounds.top); + boundsOut.offsetTo(boundedLeft, movementBounds.top); } else if (fromRight < fromLeft && fromRight < fromTop && fromRight < fromBottom) { - boundsOut.offsetTo(movementBounds.right, stackBounds.top); + boundsOut.offsetTo(movementBounds.right, boundedTop); } else { - boundsOut.offsetTo(stackBounds.left, movementBounds.bottom); + boundsOut.offsetTo(boundedLeft, movementBounds.bottom); } } diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java index 4748e6fb19ff..7ee5170ef618 100644 --- a/core/java/com/android/internal/util/NotificationColorUtil.java +++ b/core/java/com/android/internal/util/NotificationColorUtil.java @@ -268,6 +268,45 @@ public class NotificationColorUtil { } /** + * Finds a suitable color such that there's enough contrast. + * + * @param color the color to start searching from. + * @param other the color to ensure contrast against. Assumed to be darker than {@param color} + * @param findFg if true, we assume {@param color} is a foreground, otherwise a background. + * @param minRatio the minimum contrast ratio required. + * @return a color with the same hue as {@param color}, potentially darkened to meet the + * contrast ratio. + */ + public static int findContrastColorAgainstDark(int color, int other, boolean findFg, + double minRatio) { + int fg = findFg ? color : other; + int bg = findFg ? other : color; + if (ColorUtilsFromCompat.calculateContrast(fg, bg) >= minRatio) { + return color; + } + + double[] lab = new double[3]; + ColorUtilsFromCompat.colorToLAB(findFg ? fg : bg, lab); + + double low = lab[0], high = 100; + final double a = lab[1], b = lab[2]; + for (int i = 0; i < 15 && high - low > 0.00001; i++) { + final double l = (low + high) / 2; + if (findFg) { + fg = ColorUtilsFromCompat.LABToColor(l, a, b); + } else { + bg = ColorUtilsFromCompat.LABToColor(l, a, b); + } + if (ColorUtilsFromCompat.calculateContrast(fg, bg) > minRatio) { + high = l; + } else { + low = l; + } + } + return ColorUtilsFromCompat.LABToColor(high, a, b); + } + + /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color, assuming it is for large text. */ diff --git a/core/java/com/android/internal/util/ToBooleanFunction.java b/core/java/com/android/internal/util/ToBooleanFunction.java new file mode 100644 index 000000000000..83866c22976f --- /dev/null +++ b/core/java/com/android/internal/util/ToBooleanFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.util; + +import java.util.function.Function; + +/** + * Represents a function that produces an boolean-valued result. This is the + * {@code boolean}-producing primitive specialization for {@link Function}. + * + * <p>This is a <a href="package-summary.html">functional interface</a> + * whose functional method is {@link #apply(Object)}. + * + * @param <T> the type of the input to the function + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface ToBooleanFunction<T> { + + /** + * Applies this function to the given argument. + * + * @param value the function argument + * @return the function result + */ + boolean apply(T value); +} diff --git a/core/java/com/android/internal/view/OneShotPreDrawListener.java b/core/java/com/android/internal/view/OneShotPreDrawListener.java new file mode 100644 index 000000000000..98ffd82af887 --- /dev/null +++ b/core/java/com/android/internal/view/OneShotPreDrawListener.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.view; + +import android.view.View; +import android.view.ViewTreeObserver; + +/** + * An OnPreDrawListener that will remove itself after one OnPreDraw call. Typical + * usage is: + * <pre><code> + * OneShotPreDrawListener.add(view, () -> { view.doSomething(); }) + * </code></pre> + * <p> + * The onPreDraw always returns true. + * <p> + * The listener will also remove itself from the ViewTreeObserver when the view + * is detached from the view hierarchy. In that case, the Runnable will never be + * executed. + */ +public class OneShotPreDrawListener implements ViewTreeObserver.OnPreDrawListener, + View.OnAttachStateChangeListener { + private final View mView; + private ViewTreeObserver mViewTreeObserver; + private final Runnable mRunnable; + + private OneShotPreDrawListener(View view, Runnable runnable) { + mView = view; + mViewTreeObserver = view.getViewTreeObserver(); + mRunnable = runnable; + } + + /** + * Creates a OneShotPreDrawListener and adds it to view's ViewTreeObserver. + * @param view The view whose ViewTreeObserver the OnPreDrawListener should listen. + * @param runnable The Runnable to execute in the OnPreDraw (once) + * @return The added OneShotPreDrawListener. It can be removed prior to + * the onPreDraw by calling {@link #removeListener()}. + */ + public static OneShotPreDrawListener add(View view, Runnable runnable) { + OneShotPreDrawListener listener = new OneShotPreDrawListener(view, runnable); + view.getViewTreeObserver().addOnPreDrawListener(listener); + view.addOnAttachStateChangeListener(listener); + return listener; + } + + @Override + public boolean onPreDraw() { + removeListener(); + mRunnable.run(); + return true; + } + + /** + * Removes the listener from the ViewTreeObserver. This is useful to call if the + * callback should be removed prior to {@link #onPreDraw()}. + */ + public void removeListener() { + if (mViewTreeObserver.isAlive()) { + mViewTreeObserver.removeOnPreDrawListener(this); + } else { + mView.getViewTreeObserver().removeOnPreDrawListener(this); + } + mView.removeOnAttachStateChangeListener(this); + } + + @Override + public void onViewAttachedToWindow(View v) { + mViewTreeObserver = v.getViewTreeObserver(); + } + + @Override + public void onViewDetachedFromWindow(View v) { + removeListener(); + } +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 71252fb06f2f..b0bc81bd1af1 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -36,7 +36,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.Settings; import android.text.TextUtils; @@ -682,10 +682,10 @@ public class LockPatternUtils { return; } - IMountService mountService = IMountService.Stub.asInterface(service); + IStorageManager storageManager = IStorageManager.Stub.asInterface(service); try { Log.d(TAG, "Setting owner info"); - mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo); + storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo); } catch (RemoteException e) { Log.e(TAG, "Error changing user info", e); } @@ -746,9 +746,9 @@ public class LockPatternUtils { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... dummy) { - IMountService mountService = IMountService.Stub.asInterface(service); + IStorageManager storageManager = IStorageManager.Stub.asInterface(service); try { - mountService.changeEncryptionPassword(type, password); + storageManager.changeEncryptionPassword(type, password); } catch (RemoteException e) { Log.e(TAG, "Error changing encryption password", e); } @@ -1122,9 +1122,9 @@ public class LockPatternUtils { return; } - IMountService mountService = IMountService.Stub.asInterface(service); + IStorageManager storageManager = IStorageManager.Stub.asInterface(service); try { - mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0"); + storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0"); } catch (RemoteException e) { Log.e(TAG, "Error changing pattern visible state", e); } @@ -1145,9 +1145,9 @@ public class LockPatternUtils { return; } - IMountService mountService = IMountService.Stub.asInterface(service); + IStorageManager storageManager = IStorageManager.Stub.asInterface(service); try { - mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0"); + storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0"); } catch (RemoteException e) { Log.e(TAG, "Error changing password visible state", e); } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 429131bfd320..168da5fa691d 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.os.Environment; import android.os.Process; import android.os.storage.StorageManager; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -129,6 +130,9 @@ public class SystemConfig { final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps = new ArrayMap<>(); + + final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>(); + public static SystemConfig getInstance() { synchronized (SystemConfig.class) { if (sInstance == null) { @@ -194,6 +198,10 @@ public class SystemConfig { return mDisabledUntilUsedPreinstalledCarrierAssociatedApps; } + public ArraySet<String> getPrivAppPermissions(String packageName) { + return mPrivAppPermissions.get(packageName); + } + SystemConfig() { // Read configuration from system readPermissions(Environment.buildPath( @@ -507,6 +515,8 @@ public class SystemConfig { associatedPkgs.add(pkgname); } XmlUtils.skipCurrentTag(parser); + } else if ("privapp-permissions".equals(name) && allowAppConfigs) { + readPrivAppPermissions(parser); } else { XmlUtils.skipCurrentTag(parser); continue; @@ -584,4 +594,32 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); } } + + void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { + String packageName = parser.getAttributeValue(null, "package"); + if (TextUtils.isEmpty(packageName)) { + Slog.w(TAG, "package is required for <privapp-permissions> in " + + parser.getPositionDescription()); + return; + } + + ArraySet<String> permissions = mPrivAppPermissions.get(packageName); + if (permissions == null) { + permissions = new ArraySet<>(); + } + int depth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, depth)) { + String name = parser.getName(); + if ("permission".equals(name)) { + String permName = parser.getAttributeValue(null, "name"); + if (TextUtils.isEmpty(permName)) { + Slog.w(TAG, "name is required for <permission> in " + + parser.getPositionDescription()); + continue; + } + permissions.add(permName); + } + } + mPrivAppPermissions.put(packageName, permissions); + } } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 91e831074615..a4e957638406 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -211,6 +211,7 @@ LOCAL_C_INCLUDES += \ external/skia/include/private \ external/skia/src/core \ external/skia/src/effects \ + external/skia/src/image \ external/skia/src/images \ external/sqlite/dist \ external/sqlite/android \ @@ -276,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/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index 657b1ef63043..7e417b443b4b 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -93,17 +93,15 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap, if (jbitmap) { // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. - GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap); + android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap); } - sk_sp<SkShader> s = SkMakeBitmapShader(bitmap, - (SkShader::TileMode)tileModeX, - (SkShader::TileMode)tileModeY, - nullptr, - kNever_SkCopyPixelsMode, - nullptr); - - ThrowIAE_IfNull(env, s.get()); - return reinterpret_cast<jlong>(s.release()); + + sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); + sk_sp<SkShader> shader = image->makeShader((SkShader::TileMode)tileModeX, + (SkShader::TileMode)tileModeY); + + ThrowIAE_IfNull(env, shader.get()); + return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index 7fc79d29f046..c920b8d653ab 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -70,7 +70,7 @@ static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArr static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) { Typeface* face = reinterpret_cast<Typeface*>(faceHandle); - return Typeface::setDefault(face); + Typeface::setDefault(face); } /////////////////////////////////////////////////////////////////////////////// diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp index 899c2daf8bfc..8934c1e50aba 100644 --- a/core/jni/android/graphics/Utils.cpp +++ b/core/jni/android/graphics/Utils.cpp @@ -72,9 +72,6 @@ size_t AssetStreamAdaptor::read(void* buffer, size_t size) { amount = newOffset - oldOffset; } else { amount = fAsset->read(buffer, size); - if (amount <= 0) { - SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount); - } } if (amount < 0) { diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index fbccfd5532e2..4391d93721b1 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -16,26 +16,26 @@ #include "context_hub.h" +#undef LOG_NDEBUG +#undef LOG_TAG #define LOG_NDEBUG 0 #define LOG_TAG "ContextHubService" #include <inttypes.h> #include <jni.h> -#include <mutex> -#include <string.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> - -// TOOD: On master, alphabetize these and move <mutex> into this -// grouping. -#include <chrono> -#include <unordered_map> -#include <queue> +#include <string.h> #include <android-base/macros.h> #include <cutils/log.h> +#include <chrono> +#include <mutex> +#include <queue> +#include <unordered_map> + #include "JNIHelp.h" #include "core_jni_helpers.h" @@ -1180,7 +1180,6 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_, } if (setAddressSuccess && hubId >= 0) { - ALOGD("Asking HAL to remove app"); retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg); } else { ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32 diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index 1a33d9111fdb..10090a1f6942 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -34,6 +34,8 @@ #include "core_jni_helpers.h" using android::AndroidRuntime; +using android::hardware::hidl_vec; +using android::hardware::hidl_string; #define PACKAGE_PATH "android/os" #define CLASS_NAME "HwBinder" @@ -41,10 +43,15 @@ using android::AndroidRuntime; namespace android { +static jclass gArrayListClass; +static struct { + jmethodID size; + jmethodID get; +} gArrayListMethods; + static struct fields_t { jfieldID contextID; jmethodID onTransactID; - } gFields; // static @@ -199,45 +206,46 @@ static void JHwBinder_native_transact( static void JHwBinder_native_registerService( JNIEnv *env, jobject thiz, - jstring serviceNameObj, - jint versionMajor, - jint versionMinor) { + jobject interfaceChainArrayList, + jstring serviceNameObj) { if (serviceNameObj == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return; } - if (versionMajor < 0 - || versionMajor > 65535 - || versionMinor < 0 - || versionMinor > 65535) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return; - } - - const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL); - + const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL); if (serviceName == NULL) { return; // XXX exception already pending? } - using android::hidl::manager::V1_0::IServiceManager; + jint numInterfaces = env->CallIntMethod(interfaceChainArrayList, + gArrayListMethods.size); + hidl_string *strings = new hidl_string[numInterfaces]; + + for (jint i = 0; i < numInterfaces; i++) { + jstring strObj = static_cast<jstring>( + env->CallObjectMethod(interfaceChainArrayList, + gArrayListMethods.get, + i) + ); + const char * str = env->GetStringUTFChars(strObj, nullptr); + strings[i] = hidl_string(str); + env->ReleaseStringUTFChars(strObj, str); + } - const IServiceManager::Version kVersion { - .major = static_cast<uint16_t>(versionMajor), - .minor = static_cast<uint16_t>(versionMinor), - }; + hidl_vec<hidl_string> interfaceChain; + interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */); + + using android::hidl::manager::V1_0::IServiceManager; sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); bool ok = hardware::defaultServiceManager()->add( - String8(String16( - reinterpret_cast<const char16_t *>(serviceName), - env->GetStringLength(serviceNameObj))).string(), - binder, - kVersion); + interfaceChain, + serviceName, + binder); - env->ReleaseStringCritical(serviceNameObj, serviceName); + env->ReleaseStringUTFChars(serviceNameObj, serviceName); serviceName = NULL; if (ok) { @@ -251,52 +259,43 @@ static void JHwBinder_native_registerService( static jobject JHwBinder_native_getService( JNIEnv *env, jclass /* clazzObj */, - jstring serviceNameObj, - jint versionMajor, - jint versionMinor) { - if (serviceNameObj == NULL) { + jstring ifaceNameObj, + jstring serviceNameObj) { + + if (ifaceNameObj == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return NULL; } - - if (versionMajor < 0 - || versionMajor > 65535 - || versionMinor < 0 - || versionMinor > 65535) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + if (serviceNameObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); return NULL; } - const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL); - + const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL); + if (ifaceName == NULL) { + return NULL; // XXX exception already pending? + } + const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL); if (serviceName == NULL) { - return NULL; // XXX exception already pending? + env->ReleaseStringUTFChars(ifaceNameObj, ifaceName); + return NULL; // XXX exception already pending? } - using android::hidl::manager::V1_0::IServiceManager; - - const IServiceManager::Version kVersion { - .major = static_cast<uint16_t>(versionMajor), - .minor = static_cast<uint16_t>(versionMinor), - }; - LOG(INFO) << "looking for service '" - << String8(String16( - reinterpret_cast<const char16_t *>(serviceName), - env->GetStringLength(serviceNameObj))).string() + << serviceName << "'"; sp<hardware::IBinder> service; hardware::defaultServiceManager()->get( - String8(String16( - reinterpret_cast<const char16_t *>(serviceName), - env->GetStringLength(serviceNameObj))).string(), - kVersion, + ifaceName, + serviceName, [&service](sp<hardware::IBinder> out) { service = out; }); - env->ReleaseStringCritical(serviceNameObj, serviceName); + env->ReleaseStringUTFChars(ifaceNameObj, ifaceName); + ifaceName = NULL; + env->ReleaseStringUTFChars(serviceNameObj, serviceName); serviceName = NULL; if (service == NULL) { @@ -318,16 +317,21 @@ static JNINativeMethod gMethods[] = { "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", (void *)JHwBinder_native_transact }, - { "registerService", "(Ljava/lang/String;II)V", + { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V", (void *)JHwBinder_native_registerService }, - { "getService", "(Ljava/lang/String;II)L" PACKAGE_PATH "/IHwBinder;", + { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;", (void *)JHwBinder_native_getService }, }; namespace android { int register_android_os_HwBinder(JNIEnv *env) { + jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); + gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); + gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I"); + gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;"); + return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h index 6bd82e98e911..09204880881b 100644 --- a/core/jni/android_os_HwBlob.h +++ b/core/jni/android_os_HwBlob.h @@ -20,6 +20,7 @@ #include <android-base/macros.h> #include <jni.h> #include <hidl/HidlSupport.h> +#include <hwbinder/Parcel.h> #include <utils/RefBase.h> #include <utils/Vector.h> diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index 7387b294bbcd..a10d80746e46 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -26,6 +26,7 @@ #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> +#include <hidl/HidlTransportSupport.h> #include <hidl/Status.h> #include <nativehelper/ScopedLocalRef.h> @@ -267,17 +268,17 @@ static void JHwParcel_native_writeInterfaceToken( const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL); if (interfaceName) { - hardware::Parcel *parcel = - JHwParcel::GetNativeContext(env, thiz)->getParcel(); - - status_t err = parcel->writeInterfaceToken( - String16( - reinterpret_cast<const char16_t *>(interfaceName), - env->GetStringLength(interfaceNameObj))); + String8 nameCopy = String8(String16( + reinterpret_cast<const char16_t *>(interfaceName), + env->GetStringLength(interfaceNameObj))); env->ReleaseStringCritical(interfaceNameObj, interfaceName); interfaceName = NULL; + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + status_t err = parcel->writeInterfaceToken(nameCopy.string()); signalExceptionForError(env, err); } } @@ -294,17 +295,18 @@ static void JHwParcel_native_enforceInterface( const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL); if (interfaceName) { - hardware::Parcel *parcel = - JHwParcel::GetNativeContext(env, thiz)->getParcel(); - - bool valid = parcel->enforceInterface( - String16( - reinterpret_cast<const char16_t *>(interfaceName), - env->GetStringLength(interfaceNameObj))); + String8 interfaceNameCopy = String8(String16( + reinterpret_cast<const char16_t *>(interfaceName), + env->GetStringLength(interfaceNameObj))); env->ReleaseStringCritical(interfaceNameObj, interfaceName); interfaceName = NULL; + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + bool valid = parcel->enforceInterface(interfaceNameCopy.string()); + if (!valid) { jniThrowException( env, @@ -382,7 +384,7 @@ static void JHwParcel_native_writeStatus( hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); - status_t err = status.writeToParcel(parcel); + status_t err = ::android::hardware::writeToParcel(status, parcel); signalExceptionForError(env, err); } @@ -393,7 +395,7 @@ static void JHwParcel_native_verifySuccess(JNIEnv *env, jobject thiz) { JHwParcel::GetNativeContext(env, thiz)->getParcel(); Status status; - status_t err = status.readFromParcel(*parcel); + status_t err = ::android::hardware::readFromParcel(&status, *parcel); signalExceptionForError(env, err); } @@ -424,8 +426,8 @@ static void JHwParcel_native_writeString( status_t err = parcel->writeBuffer(s, sizeof(*s), &parentHandle); if (err == OK) { - err = s->writeEmbeddedToParcel( - parcel, parentHandle, 0 /* parentOffset */); + err = ::android::hardware::writeEmbeddedToParcel( + *s, parcel, parentHandle, 0 /* parentOffset */); } signalExceptionForError(env, err); @@ -452,7 +454,8 @@ static void JHwParcel_native_write ## Suffix ## Vector( \ if (err == OK) { \ size_t childHandle; \ \ - err = vec->writeEmbeddedToParcel( \ + err = ::android::hardware::writeEmbeddedToParcel( \ + *vec, \ parcel, \ parentHandle, \ 0 /* parentOffset */, \ @@ -507,7 +510,8 @@ static void JHwParcel_native_writeBoolVector( if (err == OK) { size_t childHandle; - err = vec->writeEmbeddedToParcel( + err = ::android::hardware::writeEmbeddedToParcel( + *vec, parcel, parentHandle, 0 /* parentOffset */, @@ -567,7 +571,8 @@ static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) { return NULL; } - status_t err = const_cast<hidl_string *>(s)->readEmbeddedFromParcel( + status_t err = ::android::hardware::readEmbeddedFromParcel( + const_cast<hidl_string *>(s), *parcel, parentHandle, 0 /* parentOffset */); if (err != OK) { @@ -596,8 +601,8 @@ static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \ \ size_t childHandle; \ \ - status_t err = const_cast<hidl_vec<Type> *>(vec) \ - ->readEmbeddedFromParcel( \ + status_t err = ::android::hardware::readEmbeddedFromParcel( \ + const_cast<hidl_vec<Type> *>(vec), \ *parcel, \ parentHandle, \ 0 /* parentOffset */, \ @@ -638,8 +643,8 @@ static jbooleanArray JHwParcel_native_readBoolVector( size_t childHandle; - status_t err = const_cast<hidl_vec<bool> *>(vec) - ->readEmbeddedFromParcel( + status_t err = ::android::hardware::readEmbeddedFromParcel( + const_cast<hidl_vec<bool> *>(vec), *parcel, parentHandle, 0 /* parentOffset */, @@ -700,12 +705,13 @@ static jobjectArray JHwParcel_native_readStringVector( } size_t childHandle; - status_t err = const_cast<string_vec *>(vec)->readEmbeddedFromParcel( + status_t err = ::android::hardware::readEmbeddedFromParcel( + const_cast<string_vec *>(vec), *parcel, parentHandle, 0 /* parentOffset */, &childHandle); for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) { - err = const_cast<hidl_vec<hidl_string> *>(vec) - ->readEmbeddedFromParcel( + err = android::hardware::readEmbeddedFromParcel( + const_cast<hidl_vec<hidl_string> *>(vec), *parcel, childHandle, i * sizeof(hidl_string), @@ -759,14 +765,16 @@ static void JHwParcel_native_writeStringVector( if (err == OK) { size_t childHandle; - err = vec->writeEmbeddedToParcel( + err = ::android::hardware::writeEmbeddedToParcel( + *vec, parcel, parentHandle, 0 /* parentOffset */, &childHandle); for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) { - err = (*vec)[i].writeEmbeddedToParcel( + err = ::android::hardware::writeEmbeddedToParcel( + (*vec)[i], parcel, childHandle, i * sizeof(hidl_string)); diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index 5dace6b7e536..8844fb0a261f 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -220,6 +220,11 @@ static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz) } } +static void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/) +{ + report_sysprop_change(); +} + static const JNINativeMethod method_table[] = { { "native_get", "(Ljava/lang/String;)Ljava/lang/String;", (void*) SystemProperties_getS }, @@ -235,6 +240,8 @@ static const JNINativeMethod method_table[] = { (void*) SystemProperties_set }, { "native_add_change_callback", "()V", (void*) SystemProperties_add_change_callback }, + { "native_report_sysprop_change", "()V", + (void*) SystemProperties_report_sysprop_change }, }; int register_android_os_SystemProperties(JNIEnv *env) diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index a58bc9039881..d70fbb9d3915 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -178,7 +178,11 @@ static void verifySystemIdmaps() // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined, // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR. char subdir[PROP_VALUE_MAX]; - int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir); + int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PERSIST_PROPERTY, + subdir); + if (len == 0) { + len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir); + } if (len > 0) { String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir; if (stat(overlayPath.string(), &st) == 0) { diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index 17437318470d..b9376d8c6e66 100644 --- a/core/jni/android_view_GraphicBuffer.cpp +++ b/core/jni/android_view_GraphicBuffer.cpp @@ -111,7 +111,7 @@ static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz, } status_t error; - sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error)); + sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, 1, usage, &error)); if (buffer == NULL) { if (kDebugGraphicBuffer) { ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); 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/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index af117d18bf45..da059e3bfe67 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -319,12 +319,6 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace) { // See storage config details at http://source.android.com/tech/storage/ - // Create a second private mount namespace for our process - if (unshare(CLONE_NEWNS) == -1) { - ALOGW("Failed to unshare(): %s", strerror(errno)); - return false; - } - String8 storageSource; if (mount_mode == MOUNT_EXTERNAL_DEFAULT) { storageSource = "/mnt/runtime/default"; @@ -332,10 +326,17 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, storageSource = "/mnt/runtime/read"; } else if (mount_mode == MOUNT_EXTERNAL_WRITE) { storageSource = "/mnt/runtime/write"; - } else { + } else if (!force_mount_namespace) { // Sane default of no storage visible return true; } + + // Create a second private mount namespace for our process + if (unshare(CLONE_NEWNS) == -1) { + ALOGW("Failed to unshare(): %s", strerror(errno)); + return false; + } + if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) { ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno)); @@ -449,6 +450,20 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra jstring instructionSet, jstring dataDir) { SetSigChldHandler(); + sigset_t sigchld; + sigemptyset(&sigchld); + sigaddset(&sigchld, SIGCHLD); + + // Temporarily block SIGCHLD during forks. The SIGCHLD handler might + // log, which would result in the logging FDs we close being reopened. + // This would cause failures because the FDs are not whitelisted. + // + // Note that the zygote process is single threaded at this point. + if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) { + ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed."); + } + // Close any logging related FDs before we start evaluating the list of // file descriptors. __android_log_close(); @@ -482,6 +497,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors."); } + if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) { + ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed."); + } + // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { EnableKeepCapabilities(env); @@ -609,6 +629,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra } } else if (pid > 0) { // the parent process + + // We blocked SIGCHLD prior to a fork, we unblock it here. + if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) { + ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed."); + } } return pid; } diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h index b78b8ffa2d5d..e270911de5e7 100644 --- a/core/jni/fd_utils-inl.h +++ b/core/jni/fd_utils-inl.h @@ -241,6 +241,18 @@ class FileDescriptorInfo { is_sock(false) { } + static bool StartsWith(const std::string& str, const std::string& prefix) { + return str.compare(0, prefix.size(), prefix) == 0; + } + + static bool EndsWith(const std::string& str, const std::string& suffix) { + if (suffix.size() > str.size()) { + return false; + } + + return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; + } + // Returns true iff. a given path is whitelisted. A path is whitelisted // if it belongs to the whitelist (see kPathWhitelist) or if it's a path // under /system/framework that ends with ".jar" or if it is a system @@ -252,31 +264,42 @@ class FileDescriptorInfo { } } - static const char* kFrameworksPrefix = "/system/framework/"; - static const char* kJarSuffix = ".jar"; - if (android::base::StartsWith(path, kFrameworksPrefix) - && android::base::EndsWith(path, kJarSuffix)) { + static const std::string kFrameworksPrefix = "/system/framework/"; + static const std::string kJarSuffix = ".jar"; + if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) { return true; } // Whitelist files needed for Runtime Resource Overlay, like these: // /system/vendor/overlay/framework-res.apk - // /system/vendor/overlay/PG/android-framework-runtime-resource-overlay.apk + // /system/vendor/overlay-subdir/pg/framework-res.apk + // /vendor/overlay/framework-res.apk + // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap - // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap - static const char* kOverlayDir = "/system/vendor/overlay/"; - static const char* kApkSuffix = ".apk"; + // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap + // See AssetManager.cpp for more details on overlay-subdir. + static const std::string kOverlayDir = "/system/vendor/overlay/"; + static const std::string kVendorOverlayDir = "/vendor/overlay"; + static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const std::string kApkSuffix = ".apk"; + + if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir) + || StartsWith(path, kVendorOverlayDir)) + && EndsWith(path, kApkSuffix) + && path.find("/../") == std::string::npos) { + return true; + } - if (android::base::StartsWith(path, kOverlayDir) - && android::base::EndsWith(path, kApkSuffix) + static const std::string kOverlayIdmapPrefix = "/data/resource-cache/"; + static const std::string kOverlayIdmapSuffix = ".apk@idmap"; + if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix) && path.find("/../") == std::string::npos) { return true; } - static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; - static const char* kOverlayIdmapSuffix = ".apk@idmap"; - if (android::base::StartsWith(path, kOverlayIdmapPrefix) - && android::base::EndsWith(path, kOverlayIdmapSuffix)) { + // All regular files that are placed under this path are whitelisted automatically. + static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/"; + if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) { return true; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4eebea6da46d..fbad143f5503 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -501,6 +501,10 @@ <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" /> + <!-- Added in O --> + <!-- TODO: temporary broadcast used by AutoFillManagerServiceImpl; will be removed --> + <protected-broadcast android:name="com.android.internal.autofill.action.REQUEST_AUTOFILL" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> @@ -717,6 +721,7 @@ android:priority="400" /> <!-- Allows an app to access precise location. + Alternatively, you might want {@link #ACCESS_COARSE_LOCATION}. <p>Protection level: dangerous --> <permission android:name="android.permission.ACCESS_FINE_LOCATION" @@ -726,6 +731,7 @@ android:protectionLevel="dangerous|ephemeral" /> <!-- Allows an app to access approximate location. + Alternatively, you might want {@link #ACCESS_FINE_LOCATION}. <p>Protection level: dangerous --> <permission android:name="android.permission.ACCESS_COARSE_LOCATION" @@ -2323,6 +2329,13 @@ <permission android:name="android.permission.BIND_VOICE_INTERACTION" android:protectionLevel="signature" /> + <!-- Must be required by a {@link android.service.autofill.AutoFillService}, + to ensure that only the system can bind to it. + <p>Protection level: signature + --> + <permission android:name="android.permission.BIND_AUTO_FILL" + android:protectionLevel="signature" /> + <!-- Must be required by hotword enrollment application, to ensure that only the system can interact with it. @hide <p>Not for use by third-party applications.</p> --> @@ -2937,11 +2950,11 @@ android:protectionLevel="signature" /> <!-- Must be required by an {@link - android.service.notification.NotificationRankerService to ensure that only the system can bind to it. + android.service.notification.NotificationAssistantService to ensure that only the system + can bind to it. <p>Protection level: signature - @hide This is not a third-party API (intended for system apps). --> --> - <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE" + <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE" android:protectionLevel="signature" /> <!-- Must be required by a {@link @@ -3118,6 +3131,17 @@ <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows an application to manage auto-fill sessions. + @hide <p>Not for use by third-party applications.</p> --> + <permission android:name="android.permission.MANAGE_AUTO_FILL" + android:protectionLevel="signature" /> + + <!-- Allows an app to set the theme overlay in /vendor/overlay + being used. + @hide <p>Not for use by third-party applications.</p> --> + <permission android:name="android.permission.MODIFY_THEME_OVERLAY" + android:protectionLevel="signature" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/drawable/watch_switch_track_material.xml b/core/res/res/color/watch_switch_track_color_material.xml index 79e92a331071..c7dc5d34204a 100644 --- a/core/res/res/drawable/watch_switch_track_material.xml +++ b/core/res/res/color/watch_switch_track_color_material.xml @@ -1,9 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2016 The Android Open Source Project + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -12,10 +15,8 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false"> - <bitmap android:alpha="0.1" android:src="@drawable/watch_switch_track_mtrl_alpha" /> - </item> - <item> - <bitmap android:alpha="0.2" android:src="@drawable/watch_switch_track_mtrl_alpha" /> - </item> -</selector> + <item android:state_enabled="false" + android:alpha="?attr/disabledAlpha" + android:color="?android:colorPrimary" /> + <item android:color="?android:colorPrimary" /> +</selector>
\ No newline at end of file diff --git a/core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-hdpi/watch_switch_track_mtrl.png Binary files differindex ecee3e137ef6..ecee3e137ef6 100644 --- a/core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png +++ b/core/res/res/drawable-hdpi/watch_switch_track_mtrl.png diff --git a/core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-xhdpi/watch_switch_track_mtrl.png Binary files differindex 1aa544227380..1aa544227380 100644 --- a/core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png +++ b/core/res/res/drawable-xhdpi/watch_switch_track_mtrl.png diff --git a/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl.png Binary files differindex af2042be7f59..af2042be7f59 100644 --- a/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png +++ b/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl.png diff --git a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml index 0ab56f95efbe..08eecef1da95 100644 --- a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml +++ b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml @@ -18,14 +18,14 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingTop="?attr/dialogPreferredPadding" + android:paddingBottom="8dp" android:orientation="vertical" - android:gravity="top|center_horizontal" - android:minHeight="@dimen/alert_dialog_title_height"> + android:gravity="center_horizontal|top"> <ImageView android:id="@+id/icon" android:adjustViewBounds="true" android:maxHeight="24dp" android:maxWidth="24dp" - android:layout_marginTop="8dp" android:layout_marginStart="8dp" android:layout_marginBottom="8dp" android:layout_width="wrap_content" @@ -33,7 +33,6 @@ android:src="@null" /> <TextView android:id="@+id/alertTitle" style="?android:attr/windowTitleStyle" - android:layout_marginBottom="8dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml index aefe28f7f359..dac1e324be81 100644 --- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml +++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingBottom="8dp" android:orientation="vertical" android:gravity="top|center_horizontal"> <FrameLayout @@ -30,7 +31,6 @@ android:maxHeight="24dp" android:maxWidth="24dp" android:layout_marginTop="@dimen/screen_percentage_10" - android:layout_marginBottom="8dp" android:layout_gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -38,7 +38,6 @@ </FrameLayout> <TextView android:id="@+id/alertTitle" style="?android:attr/windowTitleStyle" - android:layout_marginBottom="8dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> diff --git a/core/res/res/layout-watch/alert_dialog_material.xml b/core/res/res/layout-watch/alert_dialog_material.xml index 2fe13de2120a..960b927a0e64 100644 --- a/core/res/res/layout-watch/alert_dialog_material.xml +++ b/core/res/res/layout-watch/alert_dialog_material.xml @@ -50,7 +50,7 @@ <TextView android:id="@+id/message" android:layout_width="match_parent" android:layout_height="wrap_content" - android:gravity="@integer/config_dialogTextGravity" + android:gravity="center_horizontal|top" android:textAppearance="@style/TextAppearance.Material.Subhead" android:paddingStart="?dialogPreferredPadding" android:paddingEnd="?dialogPreferredPadding" @@ -80,7 +80,6 @@ android:layout_height="wrap_content" android:layout_gravity="bottom" android:orientation="vertical" - android:minHeight="@dimen/alert_dialog_button_bar_height" android:paddingBottom="?dialogPreferredPadding" style="?android:attr/buttonBarStyle" android:measureWithLargestChild="true"> diff --git a/core/res/res/layout-watch/preference_list_fragment_material.xml b/core/res/res/layout-watch/preference_list_fragment_material.xml index ae8f203a7ce6..22e66d513936 100644 --- a/core/res/res/layout-watch/preference_list_fragment_material.xml +++ b/core/res/res/layout-watch/preference_list_fragment_material.xml @@ -44,7 +44,7 @@ android:paddingEnd="@dimen/dialog_padding_material" android:paddingBottom="8dp" android:textAppearance="@style/TextAppearance.Material.Title" - android:gravity="center" /> + android:gravity="center_horizontal|top" /> </com.android.internal.widget.WatchHeaderListView> </FrameLayout> diff --git a/core/res/res/layout-watch/preference_widget_switch.xml b/core/res/res/layout-watch/preference_widget_switch.xml index 5881cf0c4d1e..a1a845abfe3a 100644 --- a/core/res/res/layout-watch/preference_widget_switch.xml +++ b/core/res/res/layout-watch/preference_widget_switch.xml @@ -24,7 +24,8 @@ android:thumb="@drawable/watch_switch_thumb_material_anim" android:thumbTint="@color/watch_switch_thumb_color_material" android:thumbTintMode="multiply" - android:track="@drawable/watch_switch_track_material" + android:track="@drawable/watch_switch_track_mtrl" + android:trackTint="@color/watch_switch_track_color_material" android:focusable="false" android:clickable="false" android:background="@null" /> diff --git a/core/res/res/layout/select_dialog_multichoice_material.xml b/core/res/res/layout/select_dialog_multichoice_material.xml index 36e8e57b2988..731fe1619634 100644 --- a/core/res/res/layout/select_dialog_multichoice_material.xml +++ b/core/res/res/layout/select_dialog_multichoice_material.xml @@ -26,5 +26,5 @@ android:paddingStart="@dimen/select_dialog_padding_start_material" android:paddingEnd="?attr/dialogPreferredPadding" android:drawableStart="?attr/listChoiceIndicatorMultiple" - android:drawablePadding="20dp" + android:drawablePadding="@dimen/select_dialog_drawable_padding_start_material" android:ellipsize="marquee" /> diff --git a/core/res/res/layout/select_dialog_singlechoice_material.xml b/core/res/res/layout/select_dialog_singlechoice_material.xml index 995272ad80ef..77b693058e82 100644 --- a/core/res/res/layout/select_dialog_singlechoice_material.xml +++ b/core/res/res/layout/select_dialog_singlechoice_material.xml @@ -26,5 +26,5 @@ android:paddingStart="@dimen/select_dialog_padding_start_material" android:paddingEnd="?attr/dialogPreferredPadding" android:drawableStart="?attr/listChoiceIndicatorSingle" - android:drawablePadding="20dp" + android:drawablePadding="@dimen/select_dialog_drawable_padding_start_material" android:ellipsize="marquee" /> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 5ca9f43d6329..e43f1ba76370 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Kennisgewing-volume"</string> <string name="ringtone_default" msgid="3789758980357696936">"Verstekluitoon"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Verstekluitoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Luitone"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende luitoon"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi netwerke beskikbaar</item> <item quantity="one">Wi-Fi-netwerk beskikbaar</item> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 18fc6dd7ff2e..af8c59263d02 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"የማህደረ መረጃ ክፍልፍል"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"የማሳወቂያ ክፍልፍል"</string> <string name="ringtone_default" msgid="3789758980357696936">"ነባሪ የስልክ ላይ ጥሪ"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>) ነባሪ የስልክ ላይ ጥሪ"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ምንም"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"ጥሪ ድምፆች"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"ያልታወቀ የስልክ ጥሪ ድምፅ"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">የWi-Fi አውታረ መረቦች አሉ</item> <item quantity="other">የWi-Fi አውታረ መረቦች አሉ</item> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 3451bcc83d06..b3c24e59f6d6 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1151,10 +1151,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"مستوى صوت الوسائط"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"مستوى صوت الإشعار"</string> <string name="ringtone_default" msgid="3789758980357696936">"نغمة الرنين الافتراضية"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"نغمة الرنين الافتراضية (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"لا شيء"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"نغمات الرنين"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"نغمة رنين غير معروفة"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="zero">لا تتوفر أية شبكات Wi-Fi</item> <item quantity="two">تتوفر شبكتا Wi-Fi</item> diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml index 1f0d164c817f..7e9c5082e2e8 100644 --- a/core/res/res/values-az-rAZ/strings.xml +++ b/core/res/res/values-az-rAZ/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Media həcmi"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Bildiriş səsi"</string> <string name="ringtone_default" msgid="3789758980357696936">"Defolt rinqton"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Defolt rinqton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Heç biri"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Zəng səsləri"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Naməlum rinqton"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Əlçatan Wi-Fi şəbəkələri</item> <item quantity="one">Əlçatan Wi-Fi şəbəkəsi</item> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 2509eae861f0..6caf561e366c 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1082,10 +1082,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka medija"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka obaveštenja"</string> <string name="ringtone_default" msgid="3789758980357696936">"Podrazumevani zvuk zvona"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Podrazumevani zvuk zvona (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvukovi zvona"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznati zvuk zvona"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi mreže su dostupne</item> <item quantity="few">Wi-Fi mreže su dostupne</item> diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml index f5f1e62483b1..c076db254310 100644 --- a/core/res/res/values-be-rBY/strings.xml +++ b/core/res/res/values-be-rBY/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучнасць прайгравальніка"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучнасць апавяшчэнняў"</string> <string name="ringtone_default" msgid="3789758980357696936">"Стандартны рынгтон"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Стандартны рынгтон (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Няма"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Рынгтоны"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Невядомы рынгтон"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">сетка Wi-Fi даступная</item> <item quantity="few">сеткі Wi-Fi даступныя</item> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index f6eb81093c73..2d6bdb2ed9f8 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Сила на звука"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Сила на звука при известие"</string> <string name="ringtone_default" msgid="3789758980357696936">"Стандартна мелодия"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Стандартна мелодия (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Без"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестна мелодия"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Има достъпни Wi-Fi мрежи</item> <item quantity="one">Има достъпна Wi-Fi мрежа</item> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index f873b1c3a038..21b737aa2b99 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"মিডিয়ার ভলিউম"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"বিজ্ঞপ্তির ভলিউম"</string> <string name="ringtone_default" msgid="3789758980357696936">"ডিফল্ট রিংটোন"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ডিফল্ট রিংটোন (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"কোনো কিছুই নয়"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"রিংটোনগুলি"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"অজানা রিংটোন"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item> <item quantity="other">ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item> @@ -1432,7 +1438,7 @@ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"সরান"</string> <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string> - <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"অ্যাক্সেসযোগ্যতা সক্রিয় করতে দুইটি আঙ্গুলকে চেপে নীচে ধরে রাখুন৷"</string> + <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"অ্যাক্সেসযোগ্যতা সক্রিয় করতে দুইটি আঙ্গুলকে চেপে নিচে ধরে রাখুন৷"</string> <string name="accessibility_enabled" msgid="1381972048564547685">"অ্যাক্সেসযোগ্যতা সক্ষম করা হয়েছে৷"</string> <string name="enable_accessibility_canceled" msgid="3833923257966635673">"অ্যাক্সেসযোগ্যতা বাতিল করা হয়েছে৷"</string> <string name="user_switched" msgid="3768006783166984410">"বর্তমান ব্যবহারকারী <xliff:g id="NAME">%1$s</xliff:g>৷"</string> diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml index 7cb46feabca7..80ee40753569 100644 --- a/core/res/res/values-bs-rBA/strings.xml +++ b/core/res/res/values-bs-rBA/strings.xml @@ -1084,10 +1084,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka za medijske sadržaje"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka za obavještenja"</string> <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Zadano zvono (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznato zvono"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi mreže su dostupne</item> <item quantity="few">Wi-Fi mreže su dostupne</item> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 07f6aa8ca72d..35b2918c79e1 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -596,7 +596,7 @@ <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Fax de casa"</string> <string name="phoneTypePager" msgid="7582359955394921732">"Cercapersones"</string> <string name="phoneTypeOther" msgid="1544425847868765990">"Altres"</string> - <string name="phoneTypeCallback" msgid="2712175203065678206">"Torna la trucada"</string> + <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolució de trucada"</string> <string name="phoneTypeCar" msgid="8738360689616716982">"Cotxe"</string> <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Telèfon d\'empresa"</string> <string name="phoneTypeIsdn" msgid="8022453193171370337">"XDSI"</string> @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volum de multimèdia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum de notificació"</string> <string name="ringtone_default" msgid="3789758980357696936">"So predeterminat"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"So predeterminat (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Cap"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Sons"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"So desconegut"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Xarxes Wi-Fi disponibles</item> <item quantity="one">Xarxa Wi-Fi disponible</item> @@ -1246,7 +1252,7 @@ <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"La VPN sempre activada està desconnectada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string> <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca per configurar"</string> - <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string> + <string name="upload_file" msgid="2897957172366730416">"Tria un fitxer"</string> <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string> <string name="reset" msgid="2448168080964209908">"Restableix"</string> <string name="submit" msgid="1602335572089911941">"Envia"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 0e6ba82deeaf..95a672845b0e 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Hlasitost médií"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitost oznámení"</string> <string name="ringtone_default" msgid="3789758980357696936">"Výchozí vyzváněcí tón"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Výchozí tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Žádný"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámý vyzváněcí tón"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="few">K dispozici jsou sítě Wi-Fi</item> <item quantity="many">K dispozici jsou sítě Wi-Fi</item> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 628f9bbf23cf..a628e4244e0a 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Medielydstyrke"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for meddelelser"</string> <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Ukendt ringetone"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Tilgængelige Wi-Fi-netværk</item> <item quantity="other">Tilgængelige Wi-Fi-netværk</item> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 05155ca23acf..86f2070853ad 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Medienlautstärke"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Benachrichtigungslautstärke"</string> <string name="ringtone_default" msgid="3789758980357696936">"Standard-Klingelton"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ohne"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Klingeltöne"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Unbekannter Klingelton"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">WLAN-Netzwerke verfügbar</item> <item quantity="one">WLAN-Netzwerk verfügbar</item> @@ -1226,7 +1232,7 @@ <string name="deny" msgid="2081879885755434506">"Ablehnen"</string> <string name="permission_request_notification_title" msgid="6486759795926237907">"Berechtigung angefordert"</string> <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Berechtigung angefordert\nfür Konto <xliff:g id="ACCOUNT">%s</xliff:g>"</string> - <string name="forward_intent_to_owner" msgid="1207197447013960896">"Sie verwenden diese App außerhalb Ihres Arbeitsprofils"</string> + <string name="forward_intent_to_owner" msgid="1207197447013960896">"Du verwendest diese App außerhalb deines Arbeitsprofils"</string> <string name="forward_intent_to_work" msgid="621480743856004612">"Du verwendest diese App in deinem Arbeitsprofil."</string> <string name="input_method_binding_label" msgid="1283557179944992649">"Eingabemethode"</string> <string name="sync_binding_label" msgid="3687969138375092423">"Synchronisieren"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 4283827debcb..4ce3a1f980b3 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Ένταση ήχου πολυμέσων"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ένταση ήχου ειδοποιήσεων"</string> <string name="ringtone_default" msgid="3789758980357696936">"Προεπιλεγμένος ήχος κλήσης"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Προεπ. ήχος (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Κανένας"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ήχοι κλήσης"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Άγνωστος ήχος κλήσης"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Υπάρχουν διαθέσιμα δίκτυα Wi-Fi</item> <item quantity="one">Υπάρχει διαθέσιμο δίκτυο Wi-Fi</item> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 38f2b888ae20..72c1271c07d3 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string> <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"None"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Unknown ringtone"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi networks available</item> <item quantity="one">Wi-Fi network available</item> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 38f2b888ae20..72c1271c07d3 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string> <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"None"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Unknown ringtone"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi networks available</item> <item quantity="one">Wi-Fi network available</item> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 38f2b888ae20..72c1271c07d3 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string> <string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"None"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Unknown ringtone"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi networks available</item> <item quantity="one">Wi-Fi network available</item> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 1277acc06a08..738af8c9f17b 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen de los medios"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificación"</string> <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">redes de Wi-Fi disponibles</item> <item quantity="one">red de Wi-Fi disponible</item> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 77b43b1e59d4..3c2915d4d759 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -258,7 +258,7 @@ <string name="permgrouplab_camera" msgid="4820372495894586615">"Cámara"</string> <string name="permgroupdesc_camera" msgid="3250611594678347720">"hacer fotos y grabar vídeos"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Teléfono"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"hacer y administrar llamadas de teléfono"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"hacer y administrar llamadas telefónicas"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporales"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder a datos de sensores de tus constantes vitales"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar el contenido de la ventana"</string> @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen multimedia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificaciones"</string> <string name="ringtone_default" msgid="3789758980357696936">"Tono por defecto"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Tono desconocido"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Redes Wi-Fi disponibles</item> <item quantity="one">Red Wi-Fi disponible</item> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index d7ee50c45854..96b060f14d65 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Meediumi helitugevus"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Teatise helitugevus"</string> <string name="ringtone_default" msgid="3789758980357696936">"Vaikehelin"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Vaikehelin (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Puudub"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Helinad"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Tundmatu helin"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">WiFi-võrgud on saadaval</item> <item quantity="one">WiFi-võrk on saadaval</item> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index e7f3f0205f22..6ccd864ccc39 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Euskarriaren bolumena"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jakinarazpenen bolumena"</string> <string name="ringtone_default" msgid="3789758980357696936">"Tonu lehenetsia"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tonu lehenetsia (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Bat ere ez"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuak"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Tonu ezezaguna"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi sareak erabilgarri</item> <item quantity="one">Wi-Fi sarea erabilgarri</item> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 374183fd1218..e8e61f4bdc06 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"میزان صدای رسانه"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"میزان صدای اعلان"</string> <string name="ringtone_default" msgid="3789758980357696936">"آهنگ زنگ پیشفرض"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"آهنگ زنگ پیشفرض (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"هیچکدام"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"آهنگهای زنگ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"آهنگ زنگ ناشناس"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">شبکه Wi-Fi در دسترس</item> <item quantity="other">شبکه Wi-Fi در دسترس</item> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 9b6d57c68ed6..dbfd8ba21351 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Median äänenvoimakkuus"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ilmoituksen äänenvoimakkuus"</string> <string name="ringtone_default" msgid="3789758980357696936">"Oletussoittoääni"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Oletussoittoääni (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ei mitään"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Soittoäänet"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Tuntematon soittoääni"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi-verkkoja käytettävissä</item> <item quantity="one">Wi-Fi-verkko käytettävissä</item> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 034b291dd797..501627d9ae25 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume des notifications"</string> <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Aucune"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Réseau Wi-Fi à proximité</item> <item quantity="other">Réseaux Wi-Fi à proximité</item> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 1e5f6a1a6f66..ccff4f36cb33 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume des notifications"</string> <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Aucune"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Réseau Wi-Fi disponible</item> <item quantity="other">Réseaux Wi-Fi disponibles</item> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 704667a4eebd..89a94718f6a7 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume dos elementos multimedia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume das notificacións"</string> <string name="ringtone_default" msgid="3789758980357696936">"Ton de chamada predeterminado"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Ton de chamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ningún"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Tons de chamada"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Ton de chamada descoñecido"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Redes wifi dispoñibles</item> <item quantity="one">Rede wifi dispoñible</item> diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml index cd3e7bee3864..cbb0d9e4a4e8 100644 --- a/core/res/res/values-gu-rIN/strings.xml +++ b/core/res/res/values-gu-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"મીડિયા વોલ્યુમ"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"સૂચના વૉલ્યૂમ"</string> <string name="ringtone_default" msgid="3789758980357696936">"ડિફોલ્ટ રિંગટોન"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ડિફોલ્ટ રિંગટોન (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"કોઈ નહીં"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"રિંગટોન્સ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"અજાણ રિંગટોન"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi નેટવર્ક્સ ઉપલબ્ધ</item> <item quantity="other">Wi-Fi નેટવર્ક્સ ઉપલબ્ધ</item> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index c8b325682af7..e83305262c75 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -347,14 +347,14 @@ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"ऐप्स को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके फ़ोन का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण ऐप्स आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string> <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर संवेदक एक्सेस करें (जैसे हृदय गति मॉनीटर)"</string> <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"ऐप को आपकी शारीरिक स्थिति, जैसे आपकी हृदय गति पर नज़र रखने वाले संवेदकों का डेटा एक्सेस करने देती है."</string> - <string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string> + <string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर इवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string> <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string> - <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को निजता या संवेदनशीलता पर ध्यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string> + <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर इवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर इवेंट पढ़ने देती है. इससे ऐप को निजता या संवेदनशीलता पर ध्यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string> <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string> - <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बिना कैलेंडर ईवेंट जोड़ें या संशोधित करें और अतिथियों को ईमेल भेजें"</string> - <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"ऐप्स को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे ऐप्स ,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string> - <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"ऐप को ऐसे ईवेंट जोड़ने, निकालने, बदलने देती है जिन्हें आप अपने डिवाइस पर बदल सकते हैं, जिनमें मित्रों या सहकर्मियों के ईवेंट शामिल हैं. इससे ऐप ऐसे संदेश भेज सकता है जो कैलेंडर स्वामी से आते हुए प्रतीत होते हैं या ऐप स्वामी की जानकारी के बिना ईवेंट बदल सकता है."</string> - <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"ऐप्स को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने फ़ोन पर संशोधित कर सकते हैं. इससे ऐप्स , अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string> + <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बिना कैलेंडर इवेंट जोड़ें या संशोधित करें और अतिथियों को ईमेल भेजें"</string> + <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"ऐप्स को मित्रों या सहकर्मियों के इवेंट के साथ ही वे इवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे ऐप्स ,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या इवेंट संशोधित कर सकता है."</string> + <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"ऐप को ऐसे इवेंट जोड़ने, निकालने, बदलने देती है जिन्हें आप अपने डिवाइस पर बदल सकते हैं, जिनमें मित्रों या सहकर्मियों के इवेंट शामिल हैं. इससे ऐप ऐसे संदेश भेज सकता है जो कैलेंडर स्वामी से आते हुए प्रतीत होते हैं या ऐप स्वामी की जानकारी के बिना इवेंट बदल सकता है."</string> + <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"ऐप्स को मित्रों या सहकर्मियों के इवेंट के साथ ही वे इवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने फ़ोन पर संशोधित कर सकते हैं. इससे ऐप्स , अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या इवेंट संशोधित कर सकता है."</string> <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"अतिरिक्त स्थान प्रदाता आदेशों में पहुंचे"</string> <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ऐप्स को अतिरिक्त स्थान प्रदाता आदेशों पर पहुंचने देती है. इससे ऐप्स GPS या अन्य स्थान स्रोतों के संचालन में अवरोध पहुंचा सकता है."</string> <string name="permlab_accessFineLocation" msgid="251034415460950944">"सटीक स्थान एक्सेस करें (GPS और नेटवर्क-आधारित)"</string> @@ -459,7 +459,7 @@ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्वयन बंद या चालू टॉगल करें"</string> <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"ऐप्स को किसी खाते की समन्वयन सेटिंग संशोधित करने देता है. उदाहरण के लिए, इसका उपयोग लोग ऐप्स का समन्वयन किसी खाते से सक्षम करने में हो सकता है."</string> <string name="permlab_readSyncStats" msgid="7396577451360202448">"समन्वयन आंकड़े पढ़ें"</string> - <string name="permdesc_readSyncStats" msgid="1510143761757606156">"ऐप्स को किसी खाते के समन्वयन आंकड़े, साथ ही समन्वयित ईवेंट का इतिहास और समन्वयित डेटा की मात्रा पढ़ने देता है."</string> + <string name="permdesc_readSyncStats" msgid="1510143761757606156">"ऐप्स को किसी खाते के समन्वयन आंकड़े, साथ ही समन्वयित इवेंट का इतिहास और समन्वयित डेटा की मात्रा पढ़ने देता है."</string> <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"अपने USB मेमोरी की सामग्री पढ़ें"</string> <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"अपने SD कार्ड की सामग्री पढ़ें"</string> <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"एप्लिकेशन को आपके USB मेमोरी की सामग्री पढ़ने की अनुमति देता है."</string> @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"मीडिया वॉल्यूम"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"नोटिफिकेशन वॉल्यूम"</string> <string name="ringtone_default" msgid="3789758980357696936">"डिफ़ॉल्ट रिंगटोन"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"डिफ़ॉल्ट रिंगटोन (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"कोई नहीं"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिंगटोन"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">वाई-फ़ाई नेटवर्क उपलब्ध</item> <item quantity="other">वाई-फ़ाई नेटवर्क उपलब्ध</item> @@ -1614,7 +1620,7 @@ <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"बंद रहने का समय"</string> <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"सप्ताह की रात"</string> <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"सप्ताहांत"</string> - <string name="zen_mode_default_events_name" msgid="8158334939013085363">"ईवेंट"</string> + <string name="zen_mode_default_events_name" msgid="8158334939013085363">"इवेंट"</string> <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> द्वारा म्यूट किया गया"</string> <string name="system_error_wipe_data" msgid="6608165524785354962">"आपके डिवाइस के साथ कोई आंतरिक त्रुटि हुई और यह तब तक अस्थिर रह सकता है, जब तक आप फ़ैक्टरी डेटा रीसेट नहीं करते हैं."</string> <string name="system_error_manufacturer" msgid="8086872414744210668">"आपके डिवाइस के साथ कोई आंतरिक त्रुटि हुई. विवरणों के लिए अपने निर्माता से संपर्क करें."</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 3fc334631bae..e811b94f66a9 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1082,10 +1082,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Glasnoća medija"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnoća obavijesti"</string> <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Zadana melodija zvona (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ništa"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznata melodija zvona"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Dostupne su Wi-Fi mreže</item> <item quantity="few">Dostupne su Wi-Fi mreže</item> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 825672b82f4f..b0ce160480e9 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Média hangereje"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Értesítés hangereje"</string> <string name="ringtone_default" msgid="3789758980357696936">"Alapértelmezett csengőhang"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Alap csengőhang (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Egyik sem"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Csengőhangok"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Ismeretlen csengőhang"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi hálózatok érhetők el</item> <item quantity="one">Van elérhető Wi-Fi hálózat</item> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index af7aaaf761ce..2ba22af70052 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Մեդիա ձայնի բարձրություն"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ծանուցումների ձայնի ուժգնությունը"</string> <string name="ringtone_default" msgid="3789758980357696936">"Կանխադրված զանգերանգ"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Կանխադրված զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ոչ մեկը"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Զանգերանգներ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Անհայտ զանգերանգ"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Հասանելի են Wi-Fi ցանցեր</item> <item quantity="other">Հասանելի են Wi-Fi ցանցեր</item> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 05fe8d01cdc5..09223cd5dd7f 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume media"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume pemberitahuan"</string> <string name="ringtone_default" msgid="3789758980357696936">"Nada dering default"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Nada dering default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Tidak Ada"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nada dering tidak dikenal"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Jaringan Wi-Fi tersedia</item> <item quantity="one">Jaringan Wi-Fi tersedia</item> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index cd41f51ad0c9..105a647d72fe 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Hljóðstyrkur efnisspilunar"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hljóðstyrkur tilkynninga"</string> <string name="ringtone_default" msgid="3789758980357696936">"Sjálfgefinn hringitónn"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Sjálfg. hringitónn (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ekkert"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Hringitónar"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Óþekktur hringitónn"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi net í boði</item> <item quantity="other">Wi-Fi net í boði</item> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index ec7f8f964f5e..564472e6adf1 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume contenuti multimediali"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume notifiche"</string> <string name="ringtone_default" msgid="3789758980357696936">"Suoneria predefinita"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Suoneria predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Nessuna"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Suoneria sconosciuta"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Reti Wi-Fi disponibili</item> <item quantity="one">Rete Wi-Fi disponibile</item> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 290a31ffa624..d4b9bf11b226 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"עוצמת קול של מדיה"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת קול של התראות"</string> <string name="ringtone_default" msgid="3789758980357696936">"רינגטון ברירת מחדל"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"רינגטון ברירת מחדל (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ללא"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"רינגטונים"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"רינגטון לא ידוע"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="two">יש רשתות Wi-Fi זמינות</item> <item quantity="many">יש רשתות Wi-Fi זמינות</item> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 02736ec15c59..e2432f1080fe 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"メディアの音量"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string> <string name="ringtone_default" msgid="3789758980357696936">"プリセット着信音"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"端末の基本着信音(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"なし"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"着信音"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"不明な着信音"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">複数のWi-Fiネットワークが利用できます</item> <item quantity="one">Wi-Fiネットワークが利用できます</item> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index 1e343476d7a7..5e069b6e5535 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"მედიის ხმა"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"შეტყობინების ხმა"</string> <string name="ringtone_default" msgid="3789758980357696936">"ნაგულისხმევი ზარი"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ნაგულის.ზარი (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"არც ერთი"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"ზარები"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"უცნობი ზარი"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">ხელმისაწვდომია Wi-Fi ქსელები</item> <item quantity="one">ხელმისაწვდომია Wi-Fi ქსელი</item> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index 9a227c43e7a2..729f726a8486 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Meдиа дыбысының қаттылығы"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Хабар дыбысының қаттылығы"</string> <string name="ringtone_default" msgid="3789758980357696936">"Әдепкі рингтон"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Әдепкі рингтон (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ешқандай"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Қоңырау әуендері"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Белгісіз қоңырау әуені"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi желілері қол жетімді</item> <item quantity="one">Wi-Fi желісі қол жетімді</item> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 2491f82c6e01..c3e939e6f5ce 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -1061,10 +1061,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"កម្រិតសំឡេងមេឌៀ"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"កម្រិតសំឡេងការជូនដំណឹង"</string> <string name="ringtone_default" msgid="3789758980357696936">"សំឡេងរោទ៍លំនាំដើម"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"សំឡេងរោទ៍លំនាំដើម (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"គ្មាន"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"សំឡេងរោទ៍"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"សំឡេងរោទ៍មិនស្គាល់"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">មានបណ្តាញ Wi-Fi</item> <item quantity="one">មានបណ្តាញ Wi-Fi</item> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index 732a321c2104..7f80a299cf7a 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"ಮೀಡಿಯಾ ವಾಲ್ಯೂಮ್"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"ಅಧಿಸೂಚನೆಯ ವಾಲ್ಯೂಮ್"</string> <string name="ringtone_default" msgid="3789758980357696936">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್ಟೋನ್"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್ಟೋನ್ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ಯಾವುದೂ ಇಲ್ಲ"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"ರಿಂಗ್ಟೋನ್ಗಳು"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಪರಿಚಿತ ರಿಂಗ್ಟೋನ್"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ</item> <item quantity="other">ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ</item> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index f0cfd0be70f3..444c83dd7cbb 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -254,7 +254,7 @@ <string name="permgrouplab_storage" msgid="1971118770546336966">"저장"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"기기 사진, 미디어, 파일 액세스"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"마이크"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오를 녹음할 수 있도록"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오 녹음"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"카메라"</string> <string name="permgroupdesc_camera" msgid="3250611594678347720">"사진 및 동영상 촬영"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"전화"</string> @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"미디어 볼륨"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"알림 볼륨"</string> <string name="ringtone_default" msgid="3789758980357696936">"기본 벨소리"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"없음"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"벨소리"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"알 수 없는 벨소리"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi 네트워크 사용 가능</item> <item quantity="one">Wi-Fi 네트워크 사용 가능</item> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 7a48ae58bd11..2b592bdf4588 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Медиа үнүнүн деңгээли"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Эскертме үнүнүн деңгээли"</string> <string name="ringtone_default" msgid="3789758980357696936">"Демейки рингтон"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Демейки рингтон (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Эч бир"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ринтондор"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Белгисиз рингтон"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi тармагы жеткиликтүү</item> <item quantity="one">Wi-Fi тармагы жеткиликтүү</item> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 26c90532476a..3a96743d569d 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"ລະດັບສຽງຂອງສື່"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"ລະດັບສຽງການແຈ້ງເຕືອນ"</string> <string name="ringtone_default" msgid="3789758980357696936">"ຣິງໂທນເລີ່ມຕົ້ນ"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ຣິງໂທນເລີ່ມຕົ້ນ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ບໍ່ມີ"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"ຣິງໂທນ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"ຣິງໂທນທີ່ບໍ່ຮູ້ຈັກ"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item> <item quantity="one">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index c7806f24eef6..d60a010a6f85 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Medijos garsumas"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Pranešimo apimtis"</string> <string name="ringtone_default" msgid="3789758980357696936">"Numatytasis skambėjimo tonas"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Numatytasis skambėjimo tonas („<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>“)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Nėra"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Skambėjimo tonai"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nežinomas skambėjimo tonas"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Pasiekiami „Wi-Fi“ tinklai</item> <item quantity="few">Pasiekiami „Wi-Fi“ tinklai</item> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 6ea7d6b192c0..7afb2ceda3da 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1082,10 +1082,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Multivides skaļums"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Paziņojumu skaļums"</string> <string name="ringtone_default" msgid="3789758980357696936">"Noklusējuma zvana signāls"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Noklusējuma zvana signāls (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Nav"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvana signāli"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nezināms zvana signāls"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="zero">Pieejami Wi-Fi tīkli</item> <item quantity="one">Pieejami Wi-Fi tīkli</item> 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-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 3f228203a98d..139e02a0db5b 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Јачина на звук на медиуми"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Јачина на звук на известување"</string> <string name="ringtone_default" msgid="3789758980357696936">"Стандардна мелодија"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Стандардна мелодија (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ниедна"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Непозната мелодија"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi мрежи се достапни</item> <item quantity="other">Wi-Fi мрежи се достапни</item> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index beb6a67d3cc8..fc3eb40cdc5c 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"മീഡിയ വോളിയം"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"അറിയിപ്പ് വോളിയം"</string> <string name="ringtone_default" msgid="3789758980357696936">"ഡിഫോൾട്ട് റിംഗ്ടോൺ"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ഡിഫോൾട്ട് റിംഗ്ടോൺ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ഒന്നും വേണ്ട"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"റിംഗ്ടോണുകൾ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"അജ്ഞാത റിംഗ്ടോൺ"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">വൈഫൈ നെറ്റ്വർക്കുകൾ ലഭ്യമാണ്</item> <item quantity="one">വൈഫൈ നെറ്റ്വർക്ക് ലഭ്യമാണ്</item> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index bd80f8414141..2faf163488c2 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Медиа дууны хэмжээ"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Мэдэгдлийн дууны хэмжээ"</string> <string name="ringtone_default" msgid="3789758980357696936">"Үндсэн хонхны ая"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Үндсэн хонхны ая (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Алийг нь ч биш"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Хонхны ая"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Үл мэдэгдэх хонхны ая"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi сүлжээ ашиглах боломжтой</item> <item quantity="one">Wi-Fi сүлжээ ашиглах боломжтой</item> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 758b21b7c896..99465cc641ca 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"मीडिया व्हॉल्यूम"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"सूचना व्हॉल्यूम"</string> <string name="ringtone_default" msgid="3789758980357696936">"डीफॉल्ट रिंगटोन"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"डीफॉल्ट रिंगटोन (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"काहीही नाही"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिंगटोन"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">वाय-फाय नेटवर्क उपलब्ध</item> <item quantity="other">वाय-फाय नेटवर्क उपलब्ध</item> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index 60330e571401..1e7e2810f623 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Kelantangan media"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Kelantangan pemberitahuan"</string> <string name="ringtone_default" msgid="3789758980357696936">"Nada dering lalai"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Nada dering lalai (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Tiada"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nada dering tidak diketahui"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Rangkaian Wi-Fi tersedia</item> <item quantity="one">Rangkaian Wi-Fi tersedia</item> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index c18ff7f6b8dd..99d64230f905 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"မီဒီယာအသံအတိုးအကျယ်"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"အကြောင်းကြားသံအတိုးအကျယ်"</string> <string name="ringtone_default" msgid="3789758980357696936">"မူရင်းမြည်သံ"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"မူရင်းမြည်သံ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"တစ်ခုမှမဟုတ်"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"မြည်သံများ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"မသိသောမြည်သံ"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်</item> <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်</item> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 037154375c49..324f0d7a85ea 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Medievolum"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Varslingsvolum"</string> <string name="ringtone_default" msgid="3789758980357696936">"Standard ringetone"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringelyder"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Ukjent ringetone"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi-nettverk er tilgjengelig</item> <item quantity="one">Wi-Fi-nettverk er tilgjengelig</item> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index e039927f9dd7..caf36885db42 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -1065,10 +1065,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"मिडियाको मात्रा"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"सूचना भोल्युम"</string> <string name="ringtone_default" msgid="3789758980357696936">"पूर्वनिर्धारित रिङटोन"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"पूर्वनिर्धारित रिङटोन (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"कुनै पनि होइन"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"रिङटोनहरू"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिङटोन"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi सञ्जालहरू उपलब्ध छन्</item> <item quantity="one">Wi-Fi सञ्जाल उपलब्ध छ</item> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 13218b7f7218..084830426549 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -204,9 +204,9 @@ <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Je tv wordt uitgeschakeld.."</string> <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Je horloge wordt uitgeschakeld."</string> <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Je telefoon wordt uitgeschakeld."</string> - <string name="shutdown_confirm_question" msgid="2906544768881136183">"Wilt u afsluiten?"</string> + <string name="shutdown_confirm_question" msgid="2906544768881136183">"Wil je afsluiten?"</string> <string name="reboot_safemode_title" msgid="7054509914500140361">"Opnieuw opstarten in veilige modus"</string> - <string name="reboot_safemode_confirm" msgid="55293944502784668">"Wilt u opnieuw opstarten in de veilige modus? Als u dit doet, worden alle geïnstalleerde applicaties van derden uitgeschakeld. Ze worden weer ingeschakeld als u weer opnieuw opstart."</string> + <string name="reboot_safemode_confirm" msgid="55293944502784668">"Wil je opnieuw opstarten in de veilige modus? Als u dit doet, worden alle geïnstalleerde applicaties van derden uitgeschakeld. Ze worden weer ingeschakeld als u weer opnieuw opstart."</string> <string name="recent_tasks_title" msgid="3691764623638127888">"Recent"</string> <string name="no_recent_tasks" msgid="8794906658732193473">"Geen recente apps."</string> <string name="global_actions" product="tablet" msgid="408477140088053665">"Tabletopties"</string> @@ -356,9 +356,9 @@ <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Hiermee kan de app afspraken toevoegen, verwijderen en wijzigen die u op je tv kunt aanpassen, inclusief afspraken van vrienden of collega\'s. Met deze toestemming zou de app berichten kunnen verzenden die afkomstig lijken te zijn van agenda-eigenaren of afspraken kunnen aanpassen zonder medeweten van de eigenaar."</string> <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Hiermee kan de app afspraken toevoegen, verwijderen en wijzigen die u kunt bewerken op je telefoon, inclusief afspraken van vrienden of collega\'s. Zo kan de app berichten verzenden die afkomstig lijken te zijn van agenda-eigenaren, of afspraken aanpassen zonder medeweten van de eigenaar."</string> <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"toegang tot extra opdrachten van locatieaanbieder"</string> - <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Hiermee kan de app toegang krijgen tot extra opdrachten voor de locatieprovider. De app kan hiermee de werking van GPS of andere locatiebronnen te verstoren."</string> - <string name="permlab_accessFineLocation" msgid="251034415460950944">"toegang tot precieze locatie (GPS- en netwerkgebaseerd)"</string> - <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Hiermee kan de app je precieze locatie bepalen via GPS (Global Positioning System) of netwerklocatiebronnen zoals zendmasten en wifi. Deze locatieservices moeten zijn ingeschakeld en beschikbaar zijn op je apparaat voordat de app ze kan gebruiken. Apps kunnen dit gebruiken om te bepalen waar u bent en verbruiken mogelijk extra acculading."</string> + <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Hiermee kan de app toegang krijgen tot extra opdrachten voor de locatieprovider. De app kan hiermee de werking van gps of andere locatiebronnen te verstoren."</string> + <string name="permlab_accessFineLocation" msgid="251034415460950944">"toegang tot precieze locatie (gps- en netwerkgebaseerd)"</string> + <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Hiermee kan de app je precieze locatie bepalen via gps (Global Positioning System) of netwerklocatiebronnen zoals zendmasten en wifi. Deze locatieservices moeten zijn ingeschakeld en beschikbaar zijn op je apparaat voordat de app ze kan gebruiken. Apps kunnen dit gebruiken om te bepalen waar u bent en verbruiken mogelijk extra acculading."</string> <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"toegang tot geschatte locatie (netwerkgebaseerd)"</string> <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Hiermee kan de app beschikken over je geschatte locatie. Deze locatie wordt afgeleid van locatieservices die netwerklocatiebronnen zoals zendmasten en wifi gebruiken. Deze locatieservices moeten zijn ingeschakeld en beschikbaar zijn op je apparaat voordat de app ze kan gebruiken. Apps kunnen dit gebruiken om ongeveer te bepalen waar u zich bevindt."</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"je audio-instellingen wijzigen"</string> @@ -804,7 +804,7 @@ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Hiermee kan de app berichten toevoegen aan de inbox van je voicemail."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"geolocatiemachtigingen voor browser aanpassen"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Hiermee kan de app de geolocatiemachtigingen van de browser aanpassen. Schadelijke apps kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string> - <string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string> + <string name="save_password_message" msgid="767344687139195790">"Wil je dat de browser dit wachtwoord onthoudt?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string> <string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string> <string name="save_password_never" msgid="8274330296785855105">"Nooit"</string> @@ -1010,7 +1010,7 @@ <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Melden"</string> <string name="wait" msgid="7147118217226317732">"Wachten"</string> - <string name="webpage_unresponsive" msgid="3272758351138122503">"De pagina reageert niet meer.\n\nWilt u de pagina sluiten?"</string> + <string name="webpage_unresponsive" msgid="3272758351138122503">"De pagina reageert niet meer.\n\nWil je de pagina sluiten?"</string> <string name="launch_warning_title" msgid="1547997780506713581">"App verplaatst"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string> @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meldingsvolume"</string> <string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standaardbeltoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende beltoon"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wifi-netwerken beschikbaar</item> <item quantity="one">Wifi-netwerk beschikbaar</item> @@ -1111,7 +1117,7 @@ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl de telefoon verbonden is met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string> - <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> verzendt moment een groot aantal sms-berichten. Wilt u toestaan dat deze app berichten blijft verzenden?"</string> + <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> verzendt moment een groot aantal sms-berichten. Wil je toestaan dat deze app berichten blijft verzenden?"</string> <string name="sms_control_yes" msgid="3663725993855816807">"Toestaan"</string> <string name="sms_control_no" msgid="625438561395534982">"Weigeren"</string> <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wil graag een bericht verzenden naar <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> @@ -1220,7 +1226,7 @@ <string name="dial_number_using" msgid="5789176425167573586">"Nummer bellen\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string> <string name="create_contact_using" msgid="4947405226788104538">"Contact maken\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string> <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"De volgende apps verzoeken om toegang tot je account, nu en in de toekomst."</string> - <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Wilt u dit verzoek toestaan?"</string> + <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Wil je dit verzoek toestaan?"</string> <string name="grant_permissions_header_text" msgid="6874497408201826708">"Verzoek om toegang"</string> <string name="allow" msgid="7225948811296386551">"Toestaan"</string> <string name="deny" msgid="2081879885755434506">"Weigeren"</string> @@ -1277,7 +1283,7 @@ <string name="gpsVerifYes" msgid="2346566072867213563">"Ja"</string> <string name="gpsVerifNo" msgid="1146564937346454865">"Nee"</string> <string name="sync_too_many_deletes" msgid="5296321850662746890">"Verwijderingslimiet overschreden"</string> - <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Er zijn <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> verwijderde items voor <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> , account <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> . Wat wilt u doen?"</string> + <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Er zijn <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> verwijderde items voor <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> , account <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> . Wat wil je doen?"</string> <string name="sync_really_delete" msgid="2572600103122596243">"De items verwijderen."</string> <string name="sync_undo_deletes" msgid="2941317360600338602">"Verwijderingen ongedaan maken"</string> <string name="sync_do_nothing" msgid="3743764740430821845">"Nu niets doen."</string> @@ -1333,7 +1339,7 @@ <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string> - <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Mobiele gegevenslimiet bereikt"</string> + <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Mobiele datalimiet bereikt"</string> <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Wifi-gegevenslimiet bereikt"</string> <string name="data_usage_limit_body" msgid="291731708279614081">"Gegev. onderbr. voor rest cyclus"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Gegevenslimiet 2G-3G overschreden"</string> diff --git a/core/res/res/values-notround-watch/dimens_material.xml b/core/res/res/values-notround-watch/dimens_material.xml index 9cacb117cf7b..9fdf55b8a31d 100644 --- a/core/res/res/values-notround-watch/dimens_material.xml +++ b/core/res/res/values-notround-watch/dimens_material.xml @@ -15,12 +15,16 @@ --> <resources> <dimen name="dialog_padding_material">8dp</dimen> - <dimen name="preference_fragment_padding_vertical_material">0dp</dimen> + <dimen name="preference_fragment_padding_vertical_material">8dp</dimen> - <dimen name="list_item_padding_horizontal_material">16dp</dimen> - <dimen name="list_item_padding_start_material">16dp</dimen> - <dimen name="list_item_padding_end_material">16dp</dimen> + <dimen name="list_item_padding_horizontal_material">8dp</dimen> + <dimen name="list_item_padding_start_material">8dp</dimen> + <dimen name="list_item_padding_end_material">8dp</dimen> - <dimen name="dialog_list_padding_top_no_title">8dp</dimen> - <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen> + <dimen name="dialog_list_padding_top_no_title">0dp</dimen> + <dimen name="dialog_list_padding_bottom_no_buttons">0dp</dimen> + + <!-- Dialog padding minus control padding, used to fix alignment. --> + <dimen name="select_dialog_padding_start_material">8dp</dimen> + <dimen name="select_dialog_drawable_padding_start_material">8dp</dimen> </resources> diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml index d3476aaa7f51..3e886bccb907 100644 --- a/core/res/res/values-pa-rIN/strings.xml +++ b/core/res/res/values-pa-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"ਮੀਡੀਆ ਵੌਲਿਊਮ"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</string> <string name="ringtone_default" msgid="3789758980357696936">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਰਿੰਗਟੋਨ"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਰਿੰਗਟੋਨ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ਕੋਈ ਨਹੀਂ"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"ਰਿੰਗਟੋਨਾਂ"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"ਅਗਿਆਤ ਰਿੰਗਟੋਨ"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi ਨੈੱਟਵਰਕਸ ਉਪਲਬਧ</item> <item quantity="other">Wi-Fi ਨੈੱਟਵਰਕਸ ਉਪਲਬਧ</item> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index a7571ef3be75..92a2e2a395ca 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Głośność multimediów"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Głośność powiadomień"</string> <string name="ringtone_default" msgid="3789758980357696936">"Dzwonek domyślny"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Dzwonek domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Brak"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nieznany dzwonek"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="few">Dostępne są sieci Wi-Fi</item> <item quantity="many">Dostępne są sieci Wi-Fi</item> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 24265eef7caf..bf9e15d6b1c6 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string> <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Redes Wi-Fi disponíveis</item> <item quantity="other">Redes Wi-Fi disponíveis</item> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 627021077942..e09daa513c41 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume de multimédia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume de notificações"</string> <string name="ringtone_default" msgid="3789758980357696936">"Toque predefinido"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque predefinido (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Nada"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Redes Wi-Fi disponíveis</item> <item quantity="one">Rede Wi-Fi disponível</item> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 24265eef7caf..bf9e15d6b1c6 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string> <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Redes Wi-Fi disponíveis</item> <item quantity="other">Redes Wi-Fi disponíveis</item> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 29c0a5985220..7f96d2e6afd8 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1082,10 +1082,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volumul media"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum notificare"</string> <string name="ringtone_default" msgid="3789758980357696936">"Ton de apel prestabilit"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Ton de apel prestabilit (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Niciunul"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuri de sonerie"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Ton de apel necunoscut"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="few">Rețele Wi-Fi disponibile</item> <item quantity="other">Rețele Wi-Fi disponibile</item> diff --git a/core/res/res/values-round-watch/config_material.xml b/core/res/res/values-round-watch/config_material.xml index 11798709f148..ae4a6eedf4fd 100644 --- a/core/res/res/values-round-watch/config_material.xml +++ b/core/res/res/values-round-watch/config_material.xml @@ -20,9 +20,6 @@ <!-- Don't clip on round screens so the list can scroll past the rounded edges. --> <bool name="config_preferenceFragmentClipToPadding">false</bool> - <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.TOP --> - <integer name="config_dialogTextGravity">0x00000031</integer> - <!-- The amount to offset when scrolling to a selection in an AlertDialog --> <dimen name="config_alertDialogSelectionScrollOffset">@dimen/screen_percentage_15</dimen> </resources> diff --git a/core/res/res/values-round-watch/dimens_material.xml b/core/res/res/values-round-watch/dimens_material.xml index f2de4e013a78..c8f27b1724e3 100644 --- a/core/res/res/values-round-watch/dimens_material.xml +++ b/core/res/res/values-round-watch/dimens_material.xml @@ -23,4 +23,8 @@ <dimen name="dialog_list_padding_top_no_title">@dimen/screen_percentage_15</dimen> <dimen name="dialog_list_padding_bottom_no_buttons">@dimen/screen_percentage_15</dimen> + + <!-- Dialog padding minus control padding, used to fix alignment. --> + <dimen name="select_dialog_padding_start_material">@dimen/screen_percentage_15</dimen> + <dimen name="select_dialog_drawable_padding_start_material">8dp</dimen> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index ed6c798ab066..9e25bb7293cd 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Громкость мультимедиа"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Громкость уведомлений"</string> <string name="ringtone_default" msgid="3789758980357696936">"Мелодия по умолчанию"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"По умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Без звука"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестная мелодия"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Есть доступные сети Wi-Fi</item> <item quantity="few">Есть доступные сети Wi-Fi</item> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index 91d5bbed02b5..b106464cfba7 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -1061,10 +1061,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"මාධ්ය ශබ්දය"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"දැනුම්දීමේ ශබ්ද ත්රීවතාව"</string> <string name="ringtone_default" msgid="3789758980357696936">"සුපුරුදු රින්ටෝනය සකසන්න"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"සුපුරුදු රින්ටෝනය (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"කිසිවක් නැත"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"රිගින්ටෝන"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"නොදන්නා රින්ටෝනය"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi ජාල තිබේ</item> <item quantity="other">Wi-Fi ජාල තිබේ</item> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 5c129af1d65d..50af3ccbe611 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Hlasitosť médií"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitosť upozornení"</string> <string name="ringtone_default" msgid="3789758980357696936">"Predvolený tón zvonenia"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Predvolený tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Žiadny"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Tóny zvonenia"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámy tón zvonenia"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="few">K dispozícii sú siete Wi-Fi</item> <item quantity="many">K dispozícii sú siete Wi-Fi</item> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 76f1e665f226..5bc756b7554a 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Glasnost predstavnosti"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnost obvestila"</string> <string name="ringtone_default" msgid="3789758980357696936">"Privzeta melodija zvonjenja"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Privzeta melodija zvonjenja (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Brez"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvonjenja"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Neznana melodija zvonjenja"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Na voljo so omrežja Wi-Fi</item> <item quantity="two">Na voljo so omrežja Wi-Fi</item> diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml index 0fb3ebeec3b4..1095088806a9 100644 --- a/core/res/res/values-sq-rAL/strings.xml +++ b/core/res/res/values-sq-rAL/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"volumi i klipit \"media\""</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumi i njoftimeve"</string> <string name="ringtone_default" msgid="3789758980357696936">"Zile e paracaktuar."</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Zilja e paracaktuar (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Asnjë"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Zilet"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Zile e panjohur"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Rrjete Wi-Fi ofrohen për përdorim</item> <item quantity="one">Një rrjet Wi-Fi ofrohet për përdorim</item> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index fdf8a6d23147..27d7cad02fb5 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1082,10 +1082,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Јачина звука медија"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Јачина звука обавештења"</string> <string name="ringtone_default" msgid="3789758980357696936">"Подразумевани звук звона"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Подразумевани звук звона (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Без звука"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Звукови звона"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Непознати звук звона"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Wi-Fi мреже су доступне</item> <item quantity="few">Wi-Fi мреже су доступне</item> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 340010fa86e4..b048762ca934 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolym"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Meddelandevolym"</string> <string name="ringtone_default" msgid="3789758980357696936">"Standardringsignal"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringsignal (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Okänd ringsignal"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi-nätverk är tillgängliga</item> <item quantity="one">Wi-Fi-nätverk är tillgängligt</item> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 48325465cd6b..6cfd253b6f61 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1057,10 +1057,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Sauti ya midia"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Sauti ya arifa"</string> <string name="ringtone_default" msgid="3789758980357696936">"Mlio chaguo-msingi"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Mlio chaguo-msingi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Hamna"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Toni za mlio"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Mlio amabo haujulikani"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Mitandao ya Wi-Fi inapatikana</item> <item quantity="one">Mtandao wa Wi-Fi unapatikana</item> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index f6bb25cbf94f..b39191226846 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"மீடியாவின் ஒலியளவு"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"அறிவிப்பின் ஒலியளவு"</string> <string name="ringtone_default" msgid="3789758980357696936">"இயல்புநிலை ரிங்டோன்"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"இயல்புநிலை ரிங்டோன் (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ஏதுமில்லை"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"ரிங்டோன்கள்"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"அறியப்படாத ரிங்டோன்"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">வைஃபை நெட்வொர்க்குகள் உள்ளன</item> <item quantity="one">வைஃபை நெட்வொர்க் உள்ளது</item> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index 24bfebd29e27..5ec586ffdd1e 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"మీడియా వాల్యూమ్"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"నోటిఫికేషన్ వాల్యూమ్"</string> <string name="ringtone_default" msgid="3789758980357696936">"డిఫాల్ట్ రింగ్టోన్"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"డిఫాల్ట్ రింగ్టోన్ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ఏదీ వద్దు"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"రింగ్టోన్లు"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"తెలియని రింగ్టోన్"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi నెట్వర్క్లు అందుబాటులో ఉన్నాయి</item> <item quantity="one">Wi-Fi నెట్వర్క్ అందుబాటులో ఉంది</item> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 818bb9f835cc..15cbd94291d5 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"ระดับเสียงของสื่อ"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"ระดับเสียงของการแจ้งเตือน"</string> <string name="ringtone_default" msgid="3789758980357696936">"เสียงเรียกเข้าเริ่มต้น"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"เสียงเรียกเข้าเริ่มต้น (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"ไม่มี"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"เสียงเรียกเข้า"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"ไม่ทราบเสียงเรียกเข้า"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">มีหลายเครือข่าย Wi-Fi ที่ใช้งานได้</item> <item quantity="one">มี 1 เครือข่าย Wi-Fi ที่ใช้งานได้</item> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 81c5fd052342..31666ee4f062 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Volume ng media"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume ng notification"</string> <string name="ringtone_default" msgid="3789758980357696936">"Default na ringtone"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Default na ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Wala"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Mga Ringtone"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Hindi kilalang ringtone"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Available ang mga Wi-Fi network</item> <item quantity="other">Available ang mga Wi-Fi network</item> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 99831421eda4..012606833bb7 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -773,7 +773,7 @@ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Bu sayfada kal"</string> <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nBu sayfadan ayrılmak istediğinizden emin misiniz?"</string> <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string> - <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe dokunun."</string> + <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez dokunun."</string> <string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string> <string name="setup_autofill" msgid="7103495070180590814">"Otomatik doldurma ayarla"</string> <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string> @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Medya ses düzeyi"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Bildirim ses düzeyi"</string> <string name="ringtone_default" msgid="3789758980357696936">"Varsayılan zil sesi"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Varsayılan zil sesi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Yok"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Zil sesleri"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Bilinmeyen zil sesi"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Kablosuz ağlar var</item> <item quantity="one">Kablosuz ağ var</item> @@ -1133,7 +1139,7 @@ <string name="carrier_app_dialog_button" msgid="7900235513678617329">"UYGULAMAYI AL"</string> <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ŞİMDİ DEĞİL"</string> <string name="carrier_app_notification_title" msgid="8921767385872554621">"Yeni SIM kart takıldı"</string> - <string name="carrier_app_notification_text" msgid="1132487343346050225">"Kurmak için hafifçe dokunun"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Kurmak için dokunun"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarlayın"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarihi ayarlayın"</string> <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string> @@ -1531,7 +1537,7 @@ <string name="reason_unknown" msgid="6048913880184628119">"bilinmiyor"</string> <string name="reason_service_unavailable" msgid="7824008732243903268">"Yazdırma hizmeti etkin değil"</string> <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> hizmeti yüklendi"</string> - <string name="print_service_installed_message" msgid="5897362931070459152">"Etkinleştirmek için hafifçe dokunun"</string> + <string name="print_service_installed_message" msgid="5897362931070459152">"Etkinleştirmek için dokunun"</string> <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Yönetici PIN\'ini girin"</string> <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN\'i girin"</string> <string name="restr_pin_incorrect" msgid="8571512003955077924">"Yanlış"</string> @@ -1660,9 +1666,9 @@ <string name="user_encrypted_message" msgid="4923292604515744267">"Kilidi açmak için dokunun"</string> <string name="user_encrypted_detail" msgid="5708447464349420392">"Kullanıcı verileri kilitlendi"</string> <string name="profile_encrypted_detail" msgid="3700965619978314974">"İş profili kilitlendi"</string> - <string name="profile_encrypted_message" msgid="6964994232310195874">"İş profilinin kilidini açmak için hafifçe dokunun"</string> + <string name="profile_encrypted_message" msgid="6964994232310195874">"İş profilinin kilidini açmak için dokunun"</string> <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> cihazına bağlandı"</string> - <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dosyaları görüntülemek için hafifçe dokunun"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dosyaları görüntülemek için dokunun"</string> <string name="pin_target" msgid="3052256031352291362">"Sabitle"</string> <string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string> <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index fb0fda886797..104badd52633 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1105,10 +1105,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучність медіа"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучність сповіщення"</string> <string name="ringtone_default" msgid="3789758980357696936">"Мелодія за умовчанням"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодія за умовчанням (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Немає"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодії"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Невідома мелодія"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Мережі Wi-Fi доступні</item> <item quantity="few">Мережі Wi-Fi доступні</item> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index d6eae64a9f6d..f8224f29a948 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"میڈیا والیوم"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"اطلاع کا والیوم"</string> <string name="ringtone_default" msgid="3789758980357696936">"ڈیفالٹ رنگ ٹون"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ڈیفالٹ رنگ ٹون (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"کوئی نہیں"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"رنگ ٹونز"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"نامعلوم رنگ ٹون"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi نیٹ ورکس دستیاب ہیں</item> <item quantity="one">Wi-Fi نیٹ ورک دستیاب ہے</item> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index 5b7cf74c732c..78b5400d6dc2 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Multimedia ovozi"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Eslatma tovushi"</string> <string name="ringtone_default" msgid="3789758980357696936">"Standart rington"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standart rington (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Yo‘q"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtonlar"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Noma’lum rington"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Wi-Fi tarmoqlari aniqlandi</item> <item quantity="one">Wi-Fi tarmog‘i aniqlandi</item> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 42e0b0a74868..ca5e3bcc9ff9 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Âm lượng phương tiện"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Âm lượng thông báo"</string> <string name="ringtone_default" msgid="3789758980357696936">"Nhạc chuông mặc định"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Nhạc chuông mặc định (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Không"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Nhạc chuông"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Nhạc chuông không xác định"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">Các mạng Wi-Fi khả dụng</item> <item quantity="one">Mạng Wi-Fi khả dụng</item> diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml index 18bfd4db5ae0..72f589b3d337 100644 --- a/core/res/res/values-watch/colors_material.xml +++ b/core/res/res/values-watch/colors_material.xml @@ -14,15 +14,15 @@ limitations under the License. --> <resources> - <color name="background_material_dark">#ff232e33</color> - <color name="background_floating_material_dark">#ff3e5059</color> + <color name="background_material_dark">#232E33</color> + <color name="background_floating_material_dark">#3E5059</color> - <color name="accent_material_700">#ff2e4978</color> - <color name="accent_material_light">#ff4285f4</color> - <color name="accent_material_dark">#ff5e97f6</color> - <color name="accent_material_50">#ffd0def7</color> + <color name="accent_material_700">#5385DB</color> + <color name="accent_material_light">#75A4F5</color> + <color name="accent_material_dark">#5E97F6</color> + <color name="accent_material_50">#93B7F5</color> - <color name="primary_material_dark">#4D4D4D</color> + <color name="primary_material_dark">#33ffffff</color> <color name="button_material_dark">#ff919699</color> </resources> 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-notround-watch/config_material.xml b/core/res/res/values-watch/dimens.xml index a99674f3f060..4c8b39ca92a7 100644 --- a/core/res/res/values-notround-watch/config_material.xml +++ b/core/res/res/values-watch/dimens.xml @@ -13,13 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds, only for Material theme. Do not translate. - - NOTE: The naming convention is "config_camelCaseValue". --> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.START | Gravity.TOP --> - <integer name="config_dialogTextGravity">0x00800033</integer> +<resources> + <!-- Dialog title height, not used in watch due to dynamically sized button bar --> + <dimen name="alert_dialog_title_height">0dp</dimen> + <!-- Dialog button bar height, not used in watch due to dynamically sized button bar --> + <dimen name="alert_dialog_button_bar_height">0dp</dimen> </resources> diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml index af4207ed4e6f..0053c12d9d84 100644 --- a/core/res/res/values-watch/styles_material.xml +++ b/core/res/res/values-watch/styles_material.xml @@ -98,7 +98,7 @@ please see styles_device_defaults.xml. <item name="maxLines">@empty</item> <item name="scrollHorizontally">false</item> <item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item> - <item name="gravity">@integer/config_dialogTextGravity</item> + <item name="gravity">center_horizontal|top</item> <item name="ellipsize">end</item> </style> </resources> diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml index aa1594d46516..fbe780db6fae 100644 --- a/core/res/res/values-watch/themes_device_defaults.xml +++ b/core/res/res/values-watch/themes_device_defaults.xml @@ -314,7 +314,7 @@ a similar way. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> - <item name="colorBackground">?attr/colorBackgroundFloating</item> + <item name="colorBackground">@color/background_device_default_dark</item> <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item> <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item> <item name="colorButtonNormal">@color/button_normal_device_default_dark</item> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 68e87c265e18..2126d127967b 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"媒体音量"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string> <string name="ringtone_default" msgid="3789758980357696936">"默认铃声"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"默认铃声(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"无"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"铃声"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"未知铃声"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">有可用的 WLAN 网络</item> <item quantity="one">有可用的 WLAN 网络</item> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 62bb44af8b2d..bdd9fe3ee551 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"媒體音量"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string> <string name="ringtone_default" msgid="3789758980357696936">"預設鈴聲"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"預設鈴聲 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"無"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴聲"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"不明鈴聲"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">有可用的 Wi-Fi 網絡</item> <item quantity="one">有可用的 Wi-Fi 網絡</item> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 0500c0713413..3c2146bd2789 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"媒體音量"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"通知音量"</string> <string name="ringtone_default" msgid="3789758980357696936">"預設鈴聲"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"預設鈴聲 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"無"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴聲"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"未知的鈴聲"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="other">有多個可用的 Wi-Fi 網路</item> <item quantity="one">有一個可用的 Wi-Fi 網路</item> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 849f292c196c..011e4f744d3b 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1059,10 +1059,16 @@ <string name="volume_icon_description_media" msgid="4217311719665194215">"Ivolumu yemidiya"</string> <string name="volume_icon_description_notification" msgid="7044986546477282274">"Ivolumu yesaziso"</string> <string name="ringtone_default" msgid="3789758980357696936">"Iringithoni emisiwe"</string> - <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Iringithoni ezenzakalelayo <xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>"</string> + <!-- no translation found for ringtone_default_with_actual (1767304850491060581) --> + <skip /> <string name="ringtone_silent" msgid="7937634392408977062">"Akunalutho"</string> <string name="ringtone_picker_title" msgid="3515143939175119094">"Amaringithoni"</string> - <string name="ringtone_unknown" msgid="5477919988701784788">"Iringithoni engaziwa"</string> + <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) --> + <skip /> + <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) --> + <skip /> + <!-- no translation found for ringtone_unknown (3914515995813061520) --> + <skip /> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> <item quantity="one">Amanethiwekhi we-Wi-Fi ayatholakala</item> <item quantity="other">Amanethiwekhi we-Wi-Fi ayatholakala</item> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index c3967e46c3e9..2d61e6ec3bc5 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8335,4 +8335,15 @@ i <declare-styleable name="ShortcutCategories"> <attr name="name" /> </declare-styleable> + + <!-- Attributes that are read when parsing a <font> tag, which is a child of + <font-family>. --> + <declare-styleable name="FontFamilyFont"> + <attr name="fontStyle"> + <enum name="normal" value="0" /> + <enum name="italic" value="1" /> + </attr> + <attr name="font" format="reference" /> + <attr name="fontWeight" format="integer" /> + </declare-styleable> </resources> diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml index 89691e90d46e..8f0350a887b9 100644 --- a/core/res/res/values/colors_device_defaults.xml +++ b/core/res/res/values/colors_device_defaults.xml @@ -28,10 +28,10 @@ <color name="tertiary_device_default_settings">@color/tertiary_material_settings</color> <color name="quaternary_device_default_settings">@color/quaternary_material_settings</color> - <color name="accent_device_default_700">@color/material_deep_teal_700</color> + <color name="accent_device_default_700">@color/accent_material_700</color> <color name="accent_device_default_light">@color/accent_material_light</color> <color name="accent_device_default_dark">@color/accent_material_dark</color> - <color name="accent_device_default_50">@color/material_deep_teal_50</color> + <color name="accent_device_default_50">@color/accent_material_50</color> <color name="background_device_default_dark">@color/background_material_dark</color> <color name="background_device_default_light">@color/background_material_light</color> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index 92426c6a9bca..37feff8daf7f 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -36,8 +36,10 @@ <color name="tertiary_material_settings">@color/material_blue_grey_700</color> <color name="quaternary_material_settings">@color/material_blue_grey_200</color> + <color name="accent_material_700">@color/material_deep_teal_700</color> <color name="accent_material_light">@color/material_deep_teal_500</color> <color name="accent_material_dark">@color/material_deep_teal_200</color> + <color name="accent_material_50">@color/material_deep_teal_50</color> <color name="button_material_dark">#ff5a595b</color> <color name="button_material_light">#ffd6d7d7</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ff1d383ac3d7..d4119d072a46 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1919,6 +1919,12 @@ mirror the content of the default display. --> <bool name="config_localDisplaysMirrorContent">true</bool> + <!-- The default mode for the default display. One of the following values (See Display.java): + 0 - COLOR_MODE_DEFAULT + 7 - COLOR_MODE_SRGB + --> + <integer name="config_defaultDisplayDefaultColorMode">0</integer> + <!-- When true use the linux /dev/input/event subsystem to detect the switch changes on the headphone/microphone jack. When false use the older uevent framework. --> <bool name="config_useDevInputEventForAudioJack">false</bool> @@ -2238,6 +2244,9 @@ provisioning, availability etc --> <bool name="config_carrier_wfc_ims_available">false</bool> + <!-- Whether to use voip audio mode for ims call --> + <bool name="config_use_voip_mode_for_ims">false</bool> + <bool name="config_networkSamplingWakesDevice">true</bool> <string-array translatable="false" name="config_cdma_home_system" /> @@ -2317,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"> @@ -2483,16 +2495,24 @@ <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows. These values are in DPs and will be converted to pixel sizes internally. --> - <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">10x10</string> + <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">8x8</string> <!-- Max default size [WIDTHxHEIGHT] on screen for picture-in-picture windows to fit inside. These values are in DPs and will be converted to pixel sizes internally. --> - <string translatable="false" name="config_defaultPictureInPictureSize">216x135</string> + <string translatable="false" name="config_defaultPictureInPictureSize">192x120</string> <!-- The default gravity for the picture-in-picture window. Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT --> <integer name="config_defaultPictureInPictureGravity">0x55</integer> + <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any + ratio smaller than this is considered too tall and thin to be usable. --> + <item name="config_pictureInPictureMinAspectRatio" format="float" type="dimen">0.5</item> + + <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any + ratio larger than this is considered to wide and short to be usable. --> + <item name="config_pictureInPictureMaxAspectRatio" format="float" type="dimen">2.35</item> + <!-- Controls the snap mode for the docked stack divider 0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio 1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio) 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/dimens_material.xml b/core/res/res/values/dimens_material.xml index 30e7b3137712..ebe577c73758 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -129,6 +129,7 @@ <!-- Dialog padding minus control padding, used to fix alignment. --> <dimen name="select_dialog_padding_start_material">20dp</dimen> + <dimen name="select_dialog_drawable_padding_start_material">20dp</dimen> <dimen name="seekbar_track_background_height_material">2dp</dimen> <dimen name="seekbar_track_progress_height_material">2dp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index c06a93df4687..ed685822ee51 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2756,6 +2756,9 @@ <eat-comment /> <public-group type="attr" first-id="0x01010531"> + <public name="fontStyle" /> + <public name="font" /> + <public name="fontWeight" /> </public-group> <public-group type="style" first-id="0x010302e0"> 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 92fff65efac8..c719664c38a8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -309,10 +309,13 @@ <java-symbol type="bool" name="config_supportsMultiWindow" /> <java-symbol type="bool" name="config_guestUserEphemeral" /> <java-symbol type="bool" name="config_localDisplaysMirrorContent" /> + <java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" /> <java-symbol type="bool" name="config_enableAppWidgetService" /> <java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" /> <java-symbol type="string" name="config_defaultPictureInPictureSize" /> <java-symbol type="integer" name="config_defaultPictureInPictureGravity" /> + <java-symbol type="dimen" name="config_pictureInPictureMinAspectRatio" /> + <java-symbol type="dimen" name="config_pictureInPictureMaxAspectRatio" /> <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" /> <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" /> <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" /> @@ -848,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" /> @@ -2228,6 +2233,7 @@ <java-symbol type="bool" name="config_carrier_vt_available" /> <java-symbol type="bool" name="config_device_wfc_ims_available" /> <java-symbol type="bool" name="config_carrier_wfc_ims_available" /> + <java-symbol type="bool" name="config_use_voip_mode_for_ims" /> <java-symbol type="attr" name="touchscreenBlocksFocus" /> <java-symbol type="layout" name="resolver_list_with_default" /> <java-symbol type="string" name="whichApplicationNamed" /> @@ -2292,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/core/tests/coretests/res/layout/remote_view_host.xml b/core/tests/coretests/res/layout/remote_view_host.xml index 19d0a738decc..68095081a9d9 100644 --- a/core/tests/coretests/res/layout/remote_view_host.xml +++ b/core/tests/coretests/res/layout/remote_view_host.xml @@ -19,7 +19,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/container" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent"> -</LinearLayout> + android:layout_height="match_parent" /> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml b/core/tests/coretests/res/layout/remote_views_text.xml index 532241199909..a265d2e4b21e 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml +++ b/core/tests/coretests/res/layout/remote_views_text.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2016 The Android Open Source Project ~ @@ -11,6 +12,10 @@ ~ 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. + ~ limitations under the License --> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/text" + android:layout_width="match_parent" + android:layout_height="match_parent" /> diff --git a/core/tests/coretests/res/layout/remote_views_viewstub.xml b/core/tests/coretests/res/layout/remote_views_viewstub.xml new file mode 100644 index 000000000000..d5327491ac5d --- /dev/null +++ b/core/tests/coretests/res/layout/remote_views_viewstub.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <ViewStub android:id="@+id/viewStub" + android:inflatedId="@+id/stub_inflated" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</FrameLayout> diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java index f28ba7e07ff8..e9e8bfcb09c5 100644 --- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java +++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java @@ -17,7 +17,7 @@ package android.app.activity; import android.app.Activity; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -304,10 +304,10 @@ public class BroadcastTest extends ActivityTestsBase { public void testSetSticky() throws Exception { Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); intent.putExtra("test", LaunchpadActivity.DATA_1); - ActivityManagerNative.getDefault().unbroadcastIntent(null, intent, + ActivityManager.getService().unbroadcastIntent(null, intent, UserHandle.myUserId()); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); addIntermediate("finished-broadcast"); IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1); @@ -319,9 +319,9 @@ public class BroadcastTest extends ActivityTestsBase { public void testClearSticky() throws Exception { Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); intent.putExtra("test", LaunchpadActivity.DATA_1); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); - ActivityManagerNative.getDefault().unbroadcastIntent( + ActivityManager.getService().unbroadcastIntent( null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null), UserHandle.myUserId()); addIntermediate("finished-unbroadcast"); @@ -334,10 +334,10 @@ public class BroadcastTest extends ActivityTestsBase { public void testReplaceSticky() throws Exception { Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); intent.putExtra("test", LaunchpadActivity.DATA_1); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); intent.putExtra("test", LaunchpadActivity.DATA_2); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); addIntermediate("finished-broadcast"); IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1); @@ -351,7 +351,7 @@ public class BroadcastTest extends ActivityTestsBase { public void testReceiveSticky() throws Exception { Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); intent.putExtra("test", LaunchpadActivity.DATA_1); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); runLaunchpad(LaunchpadActivity.BROADCAST_STICKY1); } @@ -361,10 +361,10 @@ public class BroadcastTest extends ActivityTestsBase { public void testReceive2Sticky() throws Exception { Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); intent.putExtra("test", LaunchpadActivity.DATA_1); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); intent = new Intent(LaunchpadActivity.BROADCAST_STICKY2, null); intent.putExtra("test", LaunchpadActivity.DATA_2); - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId()); + ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId()); runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2); } diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java index 06c495e66b6a..5af2667d29ff 100644 --- a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java @@ -21,7 +21,7 @@ import static android.net.TrafficStats.MB_IN_BYTES; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.test.AndroidTestCase; import android.util.Log; @@ -31,14 +31,14 @@ public class PackageHelperTests extends AndroidTestCase { private static final boolean localLOGV = true; public static final String TAG = "PackageHelperTests"; protected final String PREFIX = "android.content.pm"; - private IMountService mMs; + private IStorageManager mSm; private String fullId; private String fullId2; - private IMountService getMs() { + private IStorageManager getSm() { IBinder service = ServiceManager.getService("mount"); if (service != null) { - return IMountService.Stub.asInterface(service); + return IStorageManager.Stub.asInterface(service); } else { Log.e(TAG, "Can't get mount service"); } @@ -47,12 +47,12 @@ public class PackageHelperTests extends AndroidTestCase { private void cleanupContainers() throws RemoteException { Log.d(TAG,"cleanUp"); - IMountService ms = getMs(); - String[] containers = ms.getSecureContainerList(); + IStorageManager sm = getSm(); + String[] containers = sm.getSecureContainerList(); for (int i = 0; i < containers.length; i++) { if (containers[i].startsWith(PREFIX)) { Log.d(TAG,"cleaing up "+containers[i]); - ms.destroySecureContainer(containers[i], true); + sm.destroySecureContainer(containers[i], true); } } } diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index b5f06178aa3c..a15cba07e7bb 100644 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -46,7 +46,7 @@ import android.os.ServiceManager; import android.os.StatFs; import android.os.SystemClock; import android.os.UserManager; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageListener; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; @@ -1149,12 +1149,12 @@ public class PackageManagerTests extends AndroidTestCase { } } - IMountService getMs() { + IStorageManager getSm() { IBinder service = ServiceManager.getService("mount"); if (service != null) { - return IMountService.Stub.asInterface(service); + return IStorageManager.Stub.asInterface(service); } else { - Log.e(TAG, "Can't get mount service"); + Log.e(TAG, "Can't get storagemanager service"); } return null; } @@ -1185,7 +1185,7 @@ public class PackageManagerTests extends AndroidTestCase { try { // Wait on observer synchronized (observer) { - int ret = getMs().mountVolume(path); + int ret = getSm().mountVolume(path); if (ret != StorageResultCode.OperationSucceeded) { throw new Exception("Could not mount the media"); } @@ -1224,7 +1224,7 @@ public class PackageManagerTests extends AndroidTestCase { try { // Wait on observer synchronized (observer) { - getMs().unmountVolume(path, true, false); + getSm().unmountVolume(path, true, false); long waitTime = 0; while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) { observer.wait(WAIT_TIME_INCR); @@ -2754,7 +2754,7 @@ public class PackageManagerTests extends AndroidTestCase { } } - /* This test creates a stale container via MountService and then installs + /* This test creates a stale container via StorageManagerService and then installs * a package and verifies that the stale container is cleaned up and install * is successful. * Please note that this test is very closely tied to the framework's diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java index fcc638960bb8..4f2387dcf5c1 100644 --- a/core/tests/coretests/src/android/net/IpPrefixTest.java +++ b/core/tests/coretests/src/android/net/IpPrefixTest.java @@ -18,14 +18,14 @@ package android.net; import android.net.IpPrefix; import android.os.Parcel; -import static android.test.MoreAsserts.assertNotEqual; import android.test.suitebuilder.annotation.SmallTest; - -import static org.junit.Assert.assertArrayEquals; import java.net.InetAddress; import java.util.Random; import junit.framework.TestCase; +import static android.test.MoreAsserts.assertNotEqual; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; public class IpPrefixTest extends TestCase { @@ -242,25 +242,42 @@ public class IpPrefixTest extends TestCase { @SmallTest public void testHashCode() { - IpPrefix p; - int oldCode = -1; + IpPrefix p = new IpPrefix(new byte[4], 0); Random random = new Random(); for (int i = 0; i < 100; i++) { + final IpPrefix oldP = p; if (random.nextBoolean()) { // IPv4. byte[] b = new byte[4]; random.nextBytes(b); p = new IpPrefix(b, random.nextInt(33)); - assertNotEqual(oldCode, p.hashCode()); - oldCode = p.hashCode(); } else { // IPv6. byte[] b = new byte[16]; random.nextBytes(b); p = new IpPrefix(b, random.nextInt(129)); - assertNotEqual(oldCode, p.hashCode()); - oldCode = p.hashCode(); } + if (p.equals(oldP)) { + assertEquals(p.hashCode(), oldP.hashCode()); + } + if (p.hashCode() != oldP.hashCode()) { + assertNotEqual(p, oldP); + } + } + } + + @SmallTest + public void testHashCodeIsNotConstant() { + IpPrefix[] prefixes = { + new IpPrefix("2001:db8:f00::ace:d00d/127"), + new IpPrefix("192.0.2.0/23"), + new IpPrefix("::/0"), + new IpPrefix("0.0.0.0/0"), + }; + for (int i = 0; i < prefixes.length; i++) { + for (int j = i + 1; j < prefixes.length; j++) { + assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode()); + } } } diff --git a/core/tests/coretests/src/android/net/RoughtimeClientTest.java b/core/tests/coretests/src/android/net/RoughtimeClientTest.java new file mode 100644 index 000000000000..cd26804c453f --- /dev/null +++ b/core/tests/coretests/src/android/net/RoughtimeClientTest.java @@ -0,0 +1,170 @@ +/* + * 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; + +import android.net.RoughtimeClient; +import android.util.Log; +import libcore.util.HexEncoding; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.security.MessageDigest; +import java.util.Arrays; +import junit.framework.TestCase; + + +public class RoughtimeClientTest extends TestCase { + private static final String TAG = "RoughtimeClientTest"; + + private static final long TEST_TIME = 8675309; + private static final int TEST_RADIUS = 42; + + private final RoughtimeTestServer mServer = new RoughtimeTestServer(); + private final RoughtimeClient mClient = new RoughtimeClient(); + + public void testBasicWorkingRoughtimeClientQuery() throws Exception { + mServer.shouldRespond(true); + assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500)); + assertEquals(1, mServer.numRequestsReceived()); + assertEquals(1, mServer.numRepliesSent()); + } + + public void testDnsResolutionFailure() throws Exception { + mServer.shouldRespond(true); + assertFalse(mClient.requestTime("roughtime.server.doesnotexist.example", 5000)); + } + + public void testTimeoutFailure() throws Exception { + mServer.shouldRespond(false); + assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500)); + assertEquals(1, mServer.numRequestsReceived()); + assertEquals(0, mServer.numRepliesSent()); + } + + private static MessageDigest md = null; + + private static byte[] signedResponse(byte[] nonce) { + RoughtimeClient.Message signed = new RoughtimeClient.Message(); + + try { + if (md == null) { + md = MessageDigest.getInstance("SHA-512"); + } + } catch(Exception e) { + return null; + } + + md.update(new byte[]{0}); + byte[] hash = md.digest(nonce); + signed.put(RoughtimeClient.Tag.ROOT, hash); + signed.putLong(RoughtimeClient.Tag.MIDP, TEST_TIME); + signed.putInt(RoughtimeClient.Tag.RADI, TEST_RADIUS); + + return signed.serialize(); + } + + private static byte[] response(byte[] nonce) { + RoughtimeClient.Message msg = new RoughtimeClient.Message(); + + msg.put(RoughtimeClient.Tag.SREP, signedResponse(nonce)); + msg.putInt(RoughtimeClient.Tag.INDX, 0); + msg.put(RoughtimeClient.Tag.PATH, new byte[0]); + + return msg.serialize(); + } + + private static class RoughtimeTestServer { + private final Object mLock = new Object(); + private final DatagramSocket mSocket; + private final InetAddress mAddress; + private final int mPort; + private int mRcvd; + private int mSent; + private Thread mListeningThread; + private boolean mShouldRespond = true; + + public RoughtimeTestServer() { + mSocket = makeSocket(); + mAddress = mSocket.getLocalAddress(); + mPort = mSocket.getLocalPort(); + Log.d(TAG, "testing server listening on (" + mAddress + ", " + mPort + ")"); + + mListeningThread = new Thread() { + public void run() { + while (true) { + byte[] buffer = new byte[2048]; + DatagramPacket request = new DatagramPacket(buffer, buffer.length); + try { + mSocket.receive(request); + } catch (IOException e) { + Log.e(TAG, "datagram receive error: " + e); + break; + } + synchronized (mLock) { + mRcvd++; + + if (! mShouldRespond) { + continue; + } + + RoughtimeClient.Message msg = + RoughtimeClient.Message.deserialize( + Arrays.copyOf(buffer, request.getLength())); + + byte[] nonce = msg.get(RoughtimeClient.Tag.NONC); + if (nonce.length != 64) { + Log.e(TAG, "Nonce is wrong length."); + } + + try { + request.setData(response(nonce)); + mSocket.send(request); + } catch (IOException e) { + Log.e(TAG, "datagram send error: " + e); + break; + } + mSent++; + } + } + mSocket.close(); + } + }; + mListeningThread.start(); + } + + private DatagramSocket makeSocket() { + DatagramSocket socket; + try { + socket = new DatagramSocket(0, InetAddress.getLoopbackAddress()); + } catch (SocketException e) { + Log.e(TAG, "Failed to create test server socket: " + e); + return null; + } + return socket; + } + + public void shouldRespond(boolean value) { mShouldRespond = value; } + + public InetAddress getAddress() { return mAddress; } + public int getPort() { return mPort; } + public int numRequestsReceived() { synchronized (mLock) { return mRcvd; } } + public int numRepliesSent() { synchronized (mLock) { return mSent; } } + } +} diff --git a/core/tests/coretests/src/android/os/storage/AsecTests.java b/core/tests/coretests/src/android/os/storage/AsecTests.java index 4f724fe5288b..e9a810d8e843 100644 --- a/core/tests/coretests/src/android/os/storage/AsecTests.java +++ b/core/tests/coretests/src/android/os/storage/AsecTests.java @@ -50,21 +50,21 @@ public class AsecTests extends AndroidTestCase { } private void cleanupContainers() throws RemoteException { - IMountService ms = getMs(); - String[] containers = ms.getSecureContainerList(); + IStorageManager sm = getSm(); + String[] containers = sm.getSecureContainerList(); for (int i = 0; i < containers.length; i++) { if (containers[i].startsWith(SECURE_CONTAINER_PREFIX)) { if (localLOGV) Log.i(TAG, "Cleaning: " + containers[i]); - ms.destroySecureContainer(containers[i], true); + sm.destroySecureContainer(containers[i], true); } } } private boolean containerExists(String localId) throws RemoteException { - IMountService ms = getMs(); - String[] containers = ms.getSecureContainerList(); + IStorageManager sm = getSm(); + String[] containers = sm.getSecureContainerList(); String fullId = SECURE_CONTAINER_PREFIX + localId; for (int i = 0; i < containers.length; i++) { @@ -80,8 +80,8 @@ public class AsecTests extends AndroidTestCase { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; - IMountService ms = getMs(); - return ms.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(), + IStorageManager sm = getSm(); + return sm.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(), isExternal); } @@ -89,8 +89,8 @@ public class AsecTests extends AndroidTestCase { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; - IMountService ms = getMs(); - return ms.mountSecureContainer(fullId, key, android.os.Process.myUid(), true); + IStorageManager sm = getSm(); + return sm.mountSecureContainer(fullId, key, android.os.Process.myUid(), true); } private int renameContainer(String localId1, String localId2) throws Exception { @@ -98,47 +98,47 @@ public class AsecTests extends AndroidTestCase { String fullId1 = SECURE_CONTAINER_PREFIX + localId1; String fullId2 = SECURE_CONTAINER_PREFIX + localId2; - IMountService ms = getMs(); - return ms.renameSecureContainer(fullId1, fullId2); + IStorageManager sm = getSm(); + return sm.renameSecureContainer(fullId1, fullId2); } private int unmountContainer(String localId, boolean force) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; - IMountService ms = getMs(); - return ms.unmountSecureContainer(fullId, force); + IStorageManager sm = getSm(); + return sm.unmountSecureContainer(fullId, force); } private int destroyContainer(String localId, boolean force) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; - IMountService ms = getMs(); - return ms.destroySecureContainer(fullId, force); + IStorageManager sm = getSm(); + return sm.destroySecureContainer(fullId, force); } private boolean isContainerMounted(String localId) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; - IMountService ms = getMs(); - return ms.isSecureContainerMounted(fullId); + IStorageManager sm = getSm(); + return sm.isSecureContainerMounted(fullId); } - private IMountService getMs() { + private IStorageManager getSm() { IBinder service = ServiceManager.getService("mount"); if (service != null) { - return IMountService.Stub.asInterface(service); + return IStorageManager.Stub.asInterface(service); } else { - Log.e(TAG, "Can't get mount service"); + Log.e(TAG, "Can't get storagemanager service"); } return null; } private boolean isMediaMounted() throws Exception { String mPath = Environment.getExternalStorageDirectory().toString(); - String state = getMs().getVolumeState(mPath); + String state = getSm().getVolumeState(mPath); return Environment.MEDIA_MOUNTED.equals(state); } @@ -385,11 +385,11 @@ public class AsecTests extends AndroidTestCase { return; } - IMountService ms = getMs(); + IStorageManager sm = getSm(); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testUnmountBusyContainer", 4, "none", FS_FAT, true)); - String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testUnmountBusyContainer"); File f = new File(path, "reference"); @@ -408,12 +408,12 @@ public class AsecTests extends AndroidTestCase { return; } - IMountService ms = getMs(); + IStorageManager sm = getSm(); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testDestroyBusyContainer", 4, "none", FS_FAT, true)); - String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testDestroyBusyContainer"); File f = new File(path, "reference"); @@ -480,10 +480,10 @@ public class AsecTests extends AndroidTestCase { return; } - IMountService ms = getMs(); + IStorageManager sm = getSm(); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testContainerSize", 1, "none", FS_FAT, true)); - String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize"); + String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize"); byte[] buf = new byte[4096]; File f = new File(path, "reference"); @@ -495,9 +495,9 @@ public class AsecTests extends AndroidTestCase { } public void testGetSecureContainerPath_NonExistPath_Failure() throws Exception { - IMountService ms = getMs(); + IStorageManager sm = getSm(); assertNull("Getting the path for an invalid container should return null", - ms.getSecureContainerPath("jparks.broke.it")); + sm.getSecureContainerPath("jparks.broke.it")); } /*------------ Tests for unmounting volume ---*/ @@ -506,7 +506,7 @@ public class AsecTests extends AndroidTestCase { boolean getMediaState() throws Exception { String mPath = Environment.getExternalStorageDirectory().toString(); - String state = getMs().getVolumeState(mPath); + String state = getSm().getVolumeState(mPath); return Environment.MEDIA_MOUNTED.equals(state); } @@ -520,7 +520,7 @@ public class AsecTests extends AndroidTestCase { } String mPath = Environment.getExternalStorageDirectory().toString(); - int ret = getMs().mountVolume(mPath); + int ret = getSm().mountVolume(mPath); return ret == StorageResultCode.OperationSucceeded; } @@ -567,7 +567,7 @@ public class AsecTests extends AndroidTestCase { try { // Wait on observer synchronized(observer) { - getMs().unmountVolume(path, false, false); + getSm().unmountVolume(path, false, false); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { observer.wait(WAIT_TIME_INCR); @@ -634,7 +634,7 @@ public class AsecTests extends AndroidTestCase { // Wait on observer synchronized(observer) { for (int i = 0; i < 5; i++) { - getMs().unmountVolume(path, false, false); + getSm().unmountVolume(path, false, false); } long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { @@ -661,7 +661,7 @@ public class AsecTests extends AndroidTestCase { } } - class ShutdownObserver extends IMountShutdownObserver.Stub{ + class ShutdownObserver extends IStorageShutdownObserver.Stub{ private boolean doneFlag = false; int statusCode; @@ -683,10 +683,10 @@ public class AsecTests extends AndroidTestCase { } void invokeShutdown() throws Exception { - IMountService ms = getMs(); + IStorageManager sm = getSm(); ShutdownObserver observer = new ShutdownObserver(); synchronized (observer) { - ms.shutdown(observer); + sm.shutdown(observer); } } @@ -731,12 +731,12 @@ public class AsecTests extends AndroidTestCase { if (!getMediaState()) { mountMedia(); } - IMountService ms = getMs(); + IStorageManager sm = getSm(); ShutdownObserver observer = new ShutdownObserver(); synchronized (observer) { - ms.shutdown(observer); + sm.shutdown(observer); for (int i = 0; i < 4; i++) { - ms.shutdown(null); + sm.shutdown(null); } } } finally { diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java index e6d315844d72..0a32e4353e1c 100644 --- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java +++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java @@ -349,6 +349,7 @@ public class SettingsProviderTest extends AndroidTestCase { assertCanBeHandled(new Intent(Settings.ACTION_USER_DICTIONARY_SETTINGS)); assertCanBeHandled(new Intent(Settings.ACTION_WIFI_IP_SETTINGS)); assertCanBeHandled(new Intent(Settings.ACTION_WIFI_SETTINGS)); + assertCanBeHandled(new Intent(Settings.ACTION_WIFI_SAVED_NETWORK_SETTINGS)); assertCanBeHandled(new Intent(Settings.ACTION_WIRELESS_SETTINGS)); } diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java index 7ba46bed8b34..b6b0e68c7b89 100644 --- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java +++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java @@ -20,11 +20,13 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.AsyncTask; import android.os.Parcel; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.View; +import android.view.ViewGroup; import com.android.frameworks.coretests.R; @@ -38,6 +40,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; + /** * Tests for RemoteViews. */ @@ -166,4 +172,164 @@ public class RemoteViewsTest { parcel.recycle(); return size; } + + @Test + public void asyncApply_fail() throws Exception { + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_test_bad_1); + ViewAppliedListener listener = new ViewAppliedListener(); + views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener); + + boolean exceptionThrown = false; + try { + listener.waitAndGetView(); + } catch (Exception e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown); + } + + @Test + public void asyncApply() throws Exception { + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test); + views.setTextViewText(R.id.text, "Dummy"); + + View syncView = views.apply(mContext, mContainer); + + ViewAppliedListener listener = new ViewAppliedListener(); + views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener); + View asyncView = listener.waitAndGetView(); + + verifyViewTree(syncView, asyncView, "Dummy"); + } + + @Test + public void asyncApply_viewStub() throws Exception { + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_viewstub); + views.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_views_text); + // This will cause the view to be inflated + views.setViewVisibility(R.id.viewStub, View.INVISIBLE); + views.setTextViewText(R.id.stub_inflated, "Dummy"); + + View syncView = views.apply(mContext, mContainer); + + ViewAppliedListener listener = new ViewAppliedListener(); + views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener); + View asyncView = listener.waitAndGetView(); + + verifyViewTree(syncView, asyncView, "Dummy"); + } + + @Test + public void asyncApply_nestedViews() throws Exception { + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host); + views.removeAllViews(R.id.container); + views.addView(R.id.container, createViewChained(1, "row1-c1", "row1-c2", "row1-c3")); + views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2")); + views.addView(R.id.container, createViewChained(2, "row3-c1", "row3-c2")); + + View syncView = views.apply(mContext, mContainer); + + ViewAppliedListener listener = new ViewAppliedListener(); + views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener); + View asyncView = listener.waitAndGetView(); + + verifyViewTree(syncView, asyncView, + "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2", "row3-c1", "row3-c2"); + } + + @Test + public void asyncApply_viewstub_nestedViews() throws Exception { + RemoteViews viewstub = new RemoteViews(mPackage, R.layout.remote_views_viewstub); + viewstub.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_view_host); + // This will cause the view to be inflated + viewstub.setViewVisibility(R.id.viewStub, View.INVISIBLE); + viewstub.addView(R.id.stub_inflated, createViewChained(1, "row1-c1", "row1-c2", "row1-c3")); + + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host); + views.removeAllViews(R.id.container); + views.addView(R.id.container, viewstub); + views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2")); + + View syncView = views.apply(mContext, mContainer); + + ViewAppliedListener listener = new ViewAppliedListener(); + views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener); + View asyncView = listener.waitAndGetView(); + + verifyViewTree(syncView, asyncView, "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2"); + } + + private RemoteViews createViewChained(int depth, String... texts) { + RemoteViews result = new RemoteViews(mPackage, R.layout.remote_view_host); + + // Create depth + RemoteViews parent = result; + while(depth > 0) { + depth--; + RemoteViews child = new RemoteViews(mPackage, R.layout.remote_view_host); + parent.addView(R.id.container, child); + parent = child; + } + + // Add texts + for (String text : texts) { + RemoteViews child = new RemoteViews(mPackage, R.layout.remote_views_text); + child.setTextViewText(R.id.text, text); + parent.addView(R.id.container, child); + } + return result; + } + + private void verifyViewTree(View v1, View v2, String... texts) { + ArrayList<String> expectedTexts = new ArrayList<>(Arrays.asList(texts)); + verifyViewTreeRecur(v1, v2, expectedTexts); + // Verify that all expected texts were found + assertEquals(0, expectedTexts.size()); + } + + private void verifyViewTreeRecur(View v1, View v2, ArrayList<String> expectedTexts) { + assertEquals(v1.getClass(), v2.getClass()); + + if (v1 instanceof TextView) { + String text = ((TextView) v1).getText().toString(); + assertEquals(text, ((TextView) v2).getText().toString()); + // Verify that the text was one of the expected texts and remove it from the list + assertTrue(expectedTexts.remove(text)); + } else if (v1 instanceof ViewGroup) { + ViewGroup vg1 = (ViewGroup) v1; + ViewGroup vg2 = (ViewGroup) v2; + assertEquals(vg1.getChildCount(), vg2.getChildCount()); + for (int i = vg1.getChildCount() - 1; i >= 0; i--) { + verifyViewTreeRecur(vg1.getChildAt(i), vg2.getChildAt(i), expectedTexts); + } + } + } + + private class ViewAppliedListener implements RemoteViews.OnViewAppliedListener { + + private final CountDownLatch mLatch = new CountDownLatch(1); + private View mView; + private Exception mError; + + @Override + public void onViewApplied(View v) { + mView = v; + mLatch.countDown(); + } + + @Override + public void onError(Exception e) { + mError = e; + mLatch.countDown(); + } + + public View waitAndGetView() throws Exception { + mLatch.await(); + + if (mError != null) { + throw new Exception(mError); + } + return mView; + } + } } diff --git a/data/etc/Android.mk b/data/etc/Android.mk index 134ac0cacec9..6718259e4c2f 100644 --- a/data/etc/Android.mk +++ b/data/etc/Android.mk @@ -18,30 +18,17 @@ LOCAL_PATH := $(my-dir) ######################## include $(CLEAR_VARS) - LOCAL_MODULE := platform.xml - LOCAL_MODULE_CLASS := ETC - -# This will install the file in /system/etc/permissions -# LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions - LOCAL_SRC_FILES := $(LOCAL_MODULE) - include $(BUILD_PREBUILT) ######################## -#include $(CLEAR_VARS) - -#LOCAL_MODULE := required_hardware.xml - -#LOCAL_MODULE_CLASS := ETC - -# This will install the file in /system/etc/permissions -# -#LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions - -#LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(CLEAR_VARS) +LOCAL_MODULE := privapp-permissions-platform.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) -#include $(BUILD_PREBUILT) diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml new file mode 100644 index 000000000000..3fc791439901 --- /dev/null +++ b/data/etc/privapp-permissions-platform.xml @@ -0,0 +1,324 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<!-- +This XML file declares which signature|privileged permissions should be granted to privileged +applications that come with the platform +--> +<permissions> + <privapp-permissions package="com.android.backupconfirm"> + <permission name="android.permission.BACKUP"/> + <permission name="android.permission.CRYPT_KEEPER"/> + </privapp-permissions> + + <privapp-permissions package="com.android.cellbroadcastreceiver"> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> + <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/> + </privapp-permissions> + + <privapp-permissions package="com.android.contacts"> + <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> + <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/> + </privapp-permissions> + + <privapp-permissions package="com.android.defcontainer"> + <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + </privapp-permissions> + + <privapp-permissions package="com.android.dialer"> + <permission name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"/> + <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/> + <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.STOP_APP_SWITCHES"/> + <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/> + <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/> + </privapp-permissions> + + <privapp-permissions package="com.android.emergency"> + <permission name="android.permission.MANAGE_USERS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.externalstorage"> + <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + </privapp-permissions> + + <privapp-permissions package="com.android.launcher"> + <permission name="android.permission.BIND_APPWIDGET"/> + <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> + </privapp-permissions> + + <privapp-permissions package="com.android.location.fused"> + <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/> + </privapp-permissions> + + <privapp-permissions package="com.android.managedprovisioning"> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> + <permission name="android.permission.CHANGE_CONFIGURATION"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.CRYPT_KEEPER"/> + <permission name="android.permission.DELETE_PACKAGES"/> + <permission name="android.permission.INSTALL_PACKAGES"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MASTER_CLEAR"/> + <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/> + <permission name="android.permission.SET_TIME"/> + <permission name="android.permission.SET_TIME_ZONE"/> + <permission name="android.permission.SHUTDOWN"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.mms.service"> + <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/> + <permission name="android.permission.BIND_CARRIER_SERVICES"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.mtp"> + <permission name="android.permission.MANAGE_USB"/> + </privapp-permissions> + + <privapp-permissions package="com.android.musicfx"> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> + </privapp-permissions> + + <privapp-permissions package="com.android.packageinstaller"> + <permission name="android.permission.CLEAR_APP_CACHE"/> + <permission name="android.permission.DELETE_PACKAGES"/> + <permission name="android.permission.INSTALL_PACKAGES"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.phone"> + <permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/> + <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/> + <permission name="android.permission.BIND_CARRIER_SERVICES"/> + <permission name="android.permission.CALL_PRIVILEGED"/> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> + <permission name="android.permission.CHANGE_CONFIGURATION"/> + <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.DUMP"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.LOCAL_MAC_ADDRESS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> + <permission name="android.permission.READ_SEARCH_INDEXABLES"/> + <permission name="android.permission.REBOOT"/> + <permission name="android.permission.REGISTER_CALL_PROVIDER"/> + <permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/> + <permission name="android.permission.SEND_RESPOND_VIA_MESSAGE"/> + <permission name="android.permission.SET_TIME"/> + <permission name="android.permission.SET_TIME_ZONE"/> + <permission name="android.permission.SHUTDOWN"/> + <permission name="android.permission.STATUS_BAR"/> + <permission name="android.permission.STOP_APP_SWITCHES"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.UPDATE_DEVICE_STATS"/> + <permission name="android.permission.UPDATE_LOCK"/> + <permission name="android.permission.WRITE_APN_SETTINGS"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/> + <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/> + </privapp-permissions> + + <privapp-permissions package="com.android.providers.calendar"> + <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.providers.contacts"> + <permission name="android.permission.BIND_DIRECTORY_SEARCH"/> + <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.providers.downloads"> + <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/> + <permission name="android.permission.CLEAR_APP_CACHE"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.UPDATE_DEVICE_STATS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.providers.media"> + <permission name="android.permission.ACCESS_MTP"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + </privapp-permissions> + + <privapp-permissions package="com.android.providers.telephony"> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + </privapp-permissions> + + <privapp-permissions package="com.android.provision"> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.server.telecom"> + <permission name="android.permission.BIND_CONNECTION_SERVICE"/> + <permission name="android.permission.BIND_INCALL_SERVICE"/> + <permission name="android.permission.CALL_PRIVILEGED"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.STOP_APP_SWITCHES"/> + </privapp-permissions> + + <privapp-permissions package="com.android.settings"> + <permission name="android.permission.ACCESS_CHECKIN_PROPERTIES"/> + <permission name="android.permission.ACCESS_NOTIFICATIONS"/> + <permission name="android.permission.BACKUP"/> + <permission name="android.permission.BATTERY_STATS"/> + <permission name="android.permission.BLUETOOTH_PRIVILEGED"/> + <permission name="android.permission.CHANGE_CONFIGURATION"/> + <permission name="android.permission.DELETE_PACKAGES"/> + <permission name="android.permission.FORCE_STOP_PACKAGES"/> + <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> + <permission name="android.permission.MANAGE_FINGERPRINT"/> + <permission name="android.permission.MANAGE_USB"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MASTER_CLEAR"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> + <permission name="android.permission.MOVE_PACKAGE"/> + <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/> + <permission name="android.permission.PACKAGE_USAGE_STATS"/> + <permission name="android.permission.READ_SEARCH_INDEXABLES"/> + <permission name="android.permission.REBOOT"/> + <permission name="android.permission.SET_TIME"/> + <permission name="android.permission.STATUS_BAR"/> + <permission name="android.permission.TETHER_PRIVILEGED"/> + <permission name="android.permission.USER_ACTIVITY"/> + <permission name="android.permission.WRITE_APN_SETTINGS"/> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.sharedstoragebackup"> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + </privapp-permissions> + + <privapp-permissions package="com.android.shell"> + <permission name="android.permission.BACKUP"/> + <permission name="android.permission.BATTERY_STATS"/> + <permission name="android.permission.BIND_APPWIDGET"/> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> + <permission name="android.permission.CHANGE_CONFIGURATION"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.DELETE_CACHE_FILES"/> + <permission name="android.permission.DELETE_PACKAGES"/> + <permission name="android.permission.DUMP"/> + <permission name="android.permission.FORCE_STOP_PACKAGES"/> + <permission name="android.permission.GET_APP_OPS_STATS"/> + <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/> + <permission name="android.permission.INSTALL_PACKAGES"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/> + <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> + <permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/> + <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> + <permission name="android.permission.MOVE_PACKAGE"/> + <permission name="android.permission.READ_FRAME_BUFFER"/> + <permission name="android.permission.REAL_GET_TASKS"/> + <permission name="android.permission.REGISTER_CALL_PROVIDER"/> + <permission name="android.permission.REGISTER_CONNECTION_MANAGER"/> + <permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/> + <permission name="android.permission.RETRIEVE_WINDOW_CONTENT"/> + <permission name="android.permission.SET_ALWAYS_FINISH"/> + <permission name="android.permission.SET_ANIMATION_SCALE"/> + <permission name="android.permission.SET_DEBUG_APP"/> + <permission name="android.permission.SET_PROCESS_LIMIT"/> + <permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/> + <permission name="android.permission.STOP_APP_SWITCHES"/> + <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.statementservice"> + <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/> + </privapp-permissions> + + <privapp-permissions package="com.android.storagemanager"> + <permission name="android.permission.DELETE_PACKAGES"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.PACKAGE_USAGE_STATS"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.systemui"> + <permission name="android.permission.BATTERY_STATS"/> + <permission name="android.permission.BIND_APPWIDGET"/> + <permission name="android.permission.BLUETOOTH_PRIVILEGED"/> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.CONTROL_VPN"/> + <permission name="android.permission.DUMP"/> + <permission name="android.permission.GET_APP_OPS_STATS"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/> + <permission name="android.permission.MANAGE_USB"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MASTER_CLEAR"/> + <permission name="android.permission.MEDIA_CONTENT_CONTROL"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> + <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/> + <permission name="android.permission.READ_DREAM_STATE"/> + <permission name="android.permission.READ_FRAME_BUFFER"/> + <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> + <permission name="android.permission.REAL_GET_TASKS"/> + <permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/> + <permission name="android.permission.START_TASKS_FROM_RECENTS"/> + <permission name="android.permission.STATUS_BAR"/> + <permission name="android.permission.STOP_APP_SWITCHES"/> + <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/> + <permission name="android.permission.TETHER_PRIVILEGED"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.WRITE_DREAM_STATE"/> + <permission name="android.permission.WRITE_MEDIA_STORAGE"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + + <privapp-permissions package="com.android.vpndialogs"> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.CONTROL_VPN"/> + </privapp-permissions> + +</permissions>
\ No newline at end of file diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd index 619fd268aef9..b51e6d97ae0a 100644 --- a/docs/html/guide/topics/ui/settings.jd +++ b/docs/html/guide/topics/ui/settings.jd @@ -390,7 +390,9 @@ setComponent()} method.</dd> <dd>The package part of the component name, as per the {@link android.content.Intent#setComponent setComponent()} method.</dd> </dl> - +<p class="note"><strong>Note: </strong>You must use string literals as the values for these +intent attributes. You cannot use resource strings, such as <code>@string/foo</code>, to define the attributes. +</p> <h2 id="Activity">Creating a Preference Activity</h2> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 79c63ee306af..e628cf8af89d 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1241,6 +1241,11 @@ public final class Bitmap implements Parcelable { * #getAllocationByteCount()}.</p> */ public final int getByteCount() { + if (mRecycled) { + Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! " + + "This is undefined behavior!"); + return 0; + } // int result permits bitmaps up to 46,340 x 46,340 return getRowBytes() * getHeight(); } @@ -1260,6 +1265,11 @@ public final class Bitmap implements Parcelable { * @see #reconfigure(int, int, Config) */ public final int getAllocationByteCount() { + if (mRecycled) { + Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! " + + "This is undefined behavior!"); + return 0; + } return nativeGetAllocationByteCount(mNativePtr); } 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/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 40a2833977af..00b5eda6d7ff 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -15,14 +15,14 @@ package android.graphics.drawable; import android.animation.Animator; +import android.animation.Animator.AnimatorListener; import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; -import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; -import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; @@ -55,11 +55,8 @@ import android.view.RenderNodeAnimatorSetHelper; import android.view.View; import com.android.internal.R; - import com.android.internal.util.VirtualRefBasePtr; -import dalvik.annotation.optimization.FastNative; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -67,6 +64,8 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import dalvik.annotation.optimization.FastNative; + /** * This class animates properties of a {@link android.graphics.drawable.VectorDrawable} with * animations defined using {@link android.animation.ObjectAnimator} or @@ -91,9 +90,77 @@ import java.util.ArrayList; * <a name="VDExample"></a> * <li><h4>XML for the VectorDrawable containing properties to be animated</h4> * <p> - * Animations can be performed on both group and path attributes, which requires groups and paths to - * have unique names in the same VectorDrawable. Groups and paths without animations do not need to - * be named. + * Animations can be performed on the animatable attributes in + * {@link android.graphics.drawable.VectorDrawable}. These attributes will be animated by + * {@link android.animation.ObjectAnimator}. The ObjectAnimator's target can be the root element, + * a group element or a path element. The targeted elements need to be named uniquely within + * the same VectorDrawable. Elements without animation do not need to be named. + * </p> + * <p> + * Here are all the animatable attributes in {@link android.graphics.drawable.VectorDrawable}: + * <table border="2" align="center" cellpadding="5"> + * <thead> + * <tr> + * <th>Element Name</th> + * <th>Animatable attribute name</th> + * </tr> + * </thead> + * <tr> + * <td><vector></td> + * <td>alpha</td> + * </tr> + * <tr> + * <td rowspan="7"><group></td> + * <td>rotation</td> + * </tr> + * <tr> + * <td>pivotX</td> + * </tr> + * <tr> + * <td>pivotY</td> + * </tr> + * <tr> + * <td>scaleX</td> + * </tr> + * <tr> + * <td>scaleY</td> + * </tr> + * <tr> + * <td>translateX</td> + * </tr> + * <tr> + * <td>translateY</td> + * </tr> + * <tr> + * <td rowspan="8"><path></td> + * <td>pathData</td> + * </tr> + * <tr> + * <td>fillColor</td> + * </tr> + * <tr> + * <td>strokeColor</td> + * </tr> + * <tr> + * <td>strokeWidth</td> + * </tr> + * <tr> + * <td>strokeAlpha</td> + * </tr> + * <tr> + * <td>fillAlpha</td> + * </tr> + * <tr> + * <td>trimPathStart</td> + * </tr> + * <tr> + * <td>trimPathOffset</td> + * </tr> + * <tr> + * <td><clip-path></td> + * <td>pathData</td> + * </tr> + * </table> * </p> * Below is an example of a VectorDrawable defined in vectordrawable.xml. This VectorDrawable is * referred to by its file name (not including file suffix) in the @@ -121,9 +188,8 @@ import java.util.ArrayList; * <li><h4>XML for AnimatedVectorDrawable</h4> * <p> * An AnimatedVectorDrawable element has a VectorDrawable attribute, and one or more target - * element(s). The target elements can be the path or group to be animated. Each target element - * contains a name attribute that references a property (of a path or a group) to animate, and an - * animation attribute that points to an ObjectAnimator or an AnimatorSet. + * element(s). The target element can specify its target by android:name attribute, and link the + * target with the proper ObjectAnimator or AnimatorSet by android:animation attribute. * </p> * The following code sample defines an AnimatedVectorDrawable. Note that the names refer to the * groups and paths in the <a href="#VDExample">VectorDrawable XML above</a>. @@ -176,7 +242,8 @@ import java.util.ArrayList; * merge the XML files from the previous examples into one XML file: * </p> * <pre> - * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" > + * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + * xmlns:aapt="http://schemas.android.com/aapt" > * <aapt:attr name="android:drawable"> * <vector * android:height="64dp" diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index e83104deb134..3a12419c8774 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -77,36 +77,27 @@ import dalvik.system.VMRuntime; * <dl> * <dt><code>android:name</code></dt> * <dd>Defines the name of this vector drawable.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:width</code></dt> * <dd>Used to define the intrinsic width of the drawable. * This support all the dimension units, normally specified with dp.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:height</code></dt> * <dd>Used to define the intrinsic height the drawable. * This support all the dimension units, normally specified with dp.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:viewportWidth</code></dt> * <dd>Used to define the width of the viewport space. Viewport is basically * the virtual canvas where the paths are drawn on.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:viewportHeight</code></dt> * <dd>Used to define the height of the viewport space. Viewport is basically * the virtual canvas where the paths are drawn on.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:tint</code></dt> * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:tintMode</code></dt> - * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd> - * <dd>Animatable : No.</dd> + * <dd>The Porter-Duff blending mode for the tint color. Default is src_in.</dd> * <dt><code>android:autoMirrored</code></dt> * <dd>Indicates if the drawable needs to be mirrored when its layout direction is - * RTL (right-to-left).</dd> - * <dd>Animatable : No.</dd> + * RTL (right-to-left). Default is false.</dd> * <dt><code>android:alpha</code></dt> - * <dd>The opacity of this drawable.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The opacity of this drawable. Default is 1.0.</dd> * </dl></dd> * </dl> * @@ -118,32 +109,24 @@ import dalvik.system.VMRuntime; * <dl> * <dt><code>android:name</code></dt> * <dd>Defines the name of the group.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:rotation</code></dt> - * <dd>The degrees of rotation of the group.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The degrees of rotation of the group. Default is 0.</dd> * <dt><code>android:pivotX</code></dt> * <dd>The X coordinate of the pivot for the scale and rotation of the group. - * This is defined in the viewport space.</dd> - * <dd>Animatable : Yes.</dd> + * This is defined in the viewport space. Default is 0.</dd> * <dt><code>android:pivotY</code></dt> * <dd>The Y coordinate of the pivot for the scale and rotation of the group. - * This is defined in the viewport space.</dd> - * <dd>Animatable : Yes.</dd> + * This is defined in the viewport space. Default is 0.</dd> * <dt><code>android:scaleX</code></dt> - * <dd>The amount of scale on the X Coordinate.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The amount of scale on the X Coordinate. Default is 1.</dd> * <dt><code>android:scaleY</code></dt> - * <dd>The amount of scale on the Y coordinate.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The amount of scale on the Y coordinate. Default is 1.</dd> * <dt><code>android:translateX</code></dt> * <dd>The amount of translation on the X coordinate. - * This is defined in the viewport space.</dd> - * <dd>Animatable : Yes.</dd> + * This is defined in the viewport space. Default is 0.</dd> * <dt><code>android:translateY</code></dt> * <dd>The amount of translation on the Y coordinate. - * This is defined in the viewport space.</dd> - * <dd>Animatable : Yes.</dd> + * This is defined in the viewport space. Default is 0.</dd> * </dl></dd> * </dl> * @@ -153,58 +136,44 @@ import dalvik.system.VMRuntime; * <dl> * <dt><code>android:name</code></dt> * <dd>Defines the name of the path.</dd> - * <dd>Animatable : No.</dd> * <dt><code>android:pathData</code></dt> * <dd>Defines path data using exactly same format as "d" attribute * in the SVG's path data. This is defined in the viewport space.</dd> - * <dd>Animatable : Yes.</dd> * <dt><code>android:fillColor</code></dt> * <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list * or a gradient color (See {@link android.R.styleable#GradientColor} * and {@link android.R.styleable#GradientColorItem}). * If this property is animated, any value set by the animation will override the original value. * No path fill is drawn if this property is not specified.</dd> - * <dd>Animatable : Yes.</dd> * <dt><code>android:strokeColor</code></dt> * <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color * state list or a gradient color (See {@link android.R.styleable#GradientColor} * and {@link android.R.styleable#GradientColorItem}). * If this property is animated, any value set by the animation will override the original value. * No path outline is drawn if this property is not specified.</dd> - * <dd>Animatable : Yes.</dd> * <dt><code>android:strokeWidth</code></dt> - * <dd>The width a path stroke.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The width a path stroke. Default is 0.</dd> * <dt><code>android:strokeAlpha</code></dt> - * <dd>The opacity of a path stroke.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The opacity of a path stroke. Default is 1.</dd> * <dt><code>android:fillAlpha</code></dt> - * <dd>The opacity to fill the path with.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The opacity to fill the path with. Default is 1.</dd> * <dt><code>android:trimPathStart</code></dt> - * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The fraction of the path to trim from the start, in the range from 0 to 1. Default is 0.</dd> * <dt><code>android:trimPathEnd</code></dt> - * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd> - * <dd>Animatable : Yes.</dd> + * <dd>The fraction of the path to trim from the end, in the range from 0 to 1. Default is 1.</dd> * <dt><code>android:trimPathOffset</code></dt> * <dd>Shift trim region (allows showed region to include the start and end), in the range - * from 0 to 1.</dd> - * <dd>Animatable : Yes.</dd> + * from 0 to 1. Default is 0.</dd> * <dt><code>android:strokeLineCap</code></dt> - * <dd>Sets the linecap for a stroked path: butt, round, square.</dd> - * <dd>Animatable : No.</dd> + * <dd>Sets the linecap for a stroked path: butt, round, square. Default is butt.</dd> * <dt><code>android:strokeLineJoin</code></dt> - * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd> - * <dd>Animatable : No.</dd> + * <dd>Sets the lineJoin for a stroked path: miter,round,bevel. Default is miter.</dd> * <dt><code>android:strokeMiterLimit</code></dt> - * <dd>Sets the Miter limit for a stroked path.</dd> - * <dd>Animatable : No.</dd> + * <dd>Sets the Miter limit for a stroked path. Default is 4.</dd> * <dt><code>android:fillType</code></dt> - * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the - * same as SVG's "fill-rule" properties. For more details, see + * <dd>For SDK 24+, sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the + * same as SVG's "fill-rule" properties. Default is nonZero. For more details, see * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd> - * <dd>Animatable : No.</dd> * </dl></dd> * * </dl> 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/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 4fc789249c5c..e566b9d75846 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; +import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.Looper; @@ -413,6 +414,9 @@ public final class KeyChain { if (alias == null) { throw new NullPointerException("alias == null"); } + if (context == null) { + throw new NullPointerException("context == null"); + } final String keyId; try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) { @@ -630,7 +634,7 @@ public final class KeyChain { if (!mConnectedAtLeastOnce) { mConnectedAtLeastOnce = true; try { - q.put(IKeyChainService.Stub.asInterface(service)); + q.put(IKeyChainService.Stub.asInterface(Binder.allowBlocking(service))); } catch (InterruptedException e) { // will never happen, since the queue starts with one available slot } diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index ae789d649e72..e0689006d5dd 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -74,6 +74,7 @@ const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; +const char* AssetManager::OVERLAY_THEME_DIR_PERSIST_PROPERTY = "persist.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; const char* AssetManager::IDMAP_DIR = "/data/resource-cache"; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 7d1e3287bb1d..907d9145f4ea 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -3204,7 +3204,7 @@ struct ResTable::Package { Package(ResTable* _owner, const Header* _header, const ResTable_package* _package) : owner(_owner), header(_header), package(_package), typeIdOffset(0) { - if (dtohs(package->header.headerSize) == sizeof(package)) { + if (dtohs(package->header.headerSize) == sizeof(*package)) { // The package structure is the same size as the definition. // This means it contains the typeIdOffset field. typeIdOffset = package->typeIdOffset; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index 0441b9d789e2..becd307d114d 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -66,6 +66,11 @@ public: * OVERLAY_DIR. */ static const char* OVERLAY_THEME_DIR_PROPERTY; + /** + * If OVERLAY_THEME_DIR_PERSIST_PROPERTY, use it to override + * OVERLAY_THEME_DIR_PROPERTY. + */ + static const char* OVERLAY_THEME_DIR_PERSIST_PROPERTY; static const char* TARGET_PACKAGE_NAME; static const char* TARGET_APK_PATH; static const char* IDMAP_DIR; diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 8dc502ac13e4..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 \ @@ -40,6 +41,7 @@ hwui_src_files := \ renderthread/OpenGLPipeline.cpp \ renderthread/DrawFrameTask.cpp \ renderthread/EglManager.cpp \ + renderthread/VulkanManager.cpp \ renderthread/RenderProxy.cpp \ renderthread/RenderTask.cpp \ renderthread/RenderThread.cpp \ @@ -83,6 +85,7 @@ hwui_src_files := \ LayerUpdateQueue.cpp \ Matrix.cpp \ OpDumper.cpp \ + OpenGLReadback.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ @@ -95,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/Program.h b/libs/hwui/Program.h index e410d71e9676..9c4cb098b4c3 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -133,7 +133,7 @@ struct ProgramDescription { // Shaders bool hasBitmap; - bool isBitmapNpot; + bool useShaderBasedWrap; bool hasVertexAlpha; bool useShadowAlphaInterp; @@ -180,7 +180,7 @@ struct ProgramDescription { modulate = false; hasBitmap = false; - isBitmapNpot = false; + useShaderBasedWrap = false; hasGradient = false; gradientType = kGradientLinear; @@ -234,7 +234,7 @@ struct ProgramDescription { if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE; if (hasBitmap) { key |= PROGRAM_KEY_BITMAP; - if (isBitmapNpot) { + if (useShaderBasedWrap) { key |= PROGRAM_KEY_BITMAP_NPOT; key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT; key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT; diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 1afc97839b44..0c2309faf4ea 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -707,7 +707,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (blendFramebuffer) { generateBlend(shader, "blendFramebuffer", description.framebufferMode); } - if (description.isBitmapNpot) { + if (description.useShaderBasedWrap) { generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); } if (description.hasGradient) { @@ -736,7 +736,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchGradient[gradientIndex(description)]); } if (description.hasBitmap) { - if (!description.isBitmapNpot) { + if (!description.useShaderBasedWrap) { shader.append(gFS_Main_FetchBitmap); } else { shader.append(gFS_Main_FetchBitmapNpot); 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/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 7c97e770b723..5e21dfc6db8a 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -738,7 +738,7 @@ void SkiaCanvas::drawGlyphs(const uint16_t* text, const float* positions, int co void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, const SkPaint& paint, const SkPath& path, size_t start, size_t end) { const int N = end - start; - SkAutoSMalloc<1024> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform))); + SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform))); SkRSXform* xform = (SkRSXform*)storage.get(); uint16_t* glyphs = (uint16_t*)(xform + N); SkPathMeasure meas(path, false); diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 971c2a314d4c..34e6a06c3dc2 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -58,7 +58,7 @@ static inline void bindUniformColor(int slot, FloatColor color) { } static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { - caches->textureState().bindTexture(texture->id()); + caches->textureState().bindTexture(texture->target(), texture->id()); texture->setWrapST(wrapS, wrapT); } @@ -218,10 +218,13 @@ bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& model const float height = outData->bitmapTexture->height(); description->hasBitmap = true; - if (!caches.extensions().hasNPot() + // gralloc doesn't support non-clamp modes + if (hwuiBitmap->isHardware() || (!caches.extensions().hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) - && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode)) { - description->isBitmapNpot = true; + && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) { + // need non-clamp mode, but it's not supported for this draw, + // so enable custom shader logic to mimic + description->useShaderBasedWrap = true; description->bitmapWrapS = gTileModes[xy[0]]; description->bitmapWrapT = gTileModes[xy[1]]; diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index b8f7d9f01697..d6b6548c47e2 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -227,7 +227,7 @@ sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(uirenderer::renderthread::RenderThr PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat); status_t error; sp<GraphicBuffer> buffer = alloc->createGraphicBuffer(info.width(), info.height(), pixelFormat, - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER + 1, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | GraphicBuffer::USAGE_SW_READ_NEVER , &error); if (!buffer.get()) { @@ -413,7 +413,6 @@ void* Bitmap::getStorage() const { case PixelStorageType::Heap: return mPixelStorage.heap.address; case PixelStorageType::Hardware: - LOG_ALWAYS_FATAL_IF("Can't get address for hardware bitmap"); return nullptr; } } @@ -460,13 +459,20 @@ 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); +} + +void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) { + outBitmap->setInfo(info(), rowBytes()); + outBitmap->setPixelRef(this); outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); } diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 3940381edf62..663238ca43f2 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -85,6 +85,10 @@ public: void getSkBitmap(SkBitmap* outBitmap); + // Ugly hack: in case of hardware bitmaps, it sets nullptr as pixels pointer + // so it would crash if anyone tries to render this bitmap. + void getSkBitmapForShaders(SkBitmap* outBitmap); + int getAshmemFd() const; size_t getAllocationByteCount() const; 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 50bc6c383a0f..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> @@ -114,4 +118,34 @@ void Typeface::setDefault(Typeface* face) { gDefaultTypeface = face; } +void Typeface::setRobotoTypefaceForTest() { + const char* kRobotoFont = "/system/fonts/Roboto-Regular.ttf"; + + 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), data, st.st_size, 0); + family->addFont(font); + font->Unref(); + + std::vector<minikin::FontFamily*> typefaces = { family }; + minikin::FontCollection *collection = new minikin::FontCollection(typefaces); + family->Unref(); + + Typeface* hwTypeface = new Typeface(); + hwTypeface->fFontCollection = collection; + hwTypeface->fSkiaStyle = SkTypeface::kNormal; + hwTypeface->fBaseWeight = 400; + hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */); + + Typeface::setDefault(hwTypeface); +} + } diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index ed0a7ebd56ae..1be630c1e978 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -48,6 +48,9 @@ struct ANDROID_API Typeface { static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families); static void setDefault(Typeface* face); + + // Sets roboto font as the default typeface for testing purpose. + static void setRobotoTypefaceForTest(); }; } diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk index dca78b38e942..37126a69f701 100644 --- a/libs/hwui/hwui_static_deps.mk +++ b/libs/hwui/hwui_static_deps.mk @@ -18,6 +18,7 @@ LOCAL_SHARED_LIBRARIES += \ libutils \ libEGL \ libGLESv2 \ + libvulkan \ libskia \ libui \ libgui \ 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/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index accbabda5a2f..7dcbbd059e88 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -164,6 +164,14 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { paint = &tmpPaint; } renderNode->getLayerSurface()->draw(canvas, 0, 0, paint); + + if (CC_UNLIKELY(Properties::debugLayersUpdates + && !renderNode->getSkiaLayer()->hasRenderedSinceRepaint)) { + renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true; + SkPaint layerPaint; + layerPaint.setColor(0x7f00ff00); + canvas->drawRect(bounds, layerPaint); + } // composing a software layer with alpha } else if (properties.effectiveLayerType() == LayerType::Software) { SkPaint paint; diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp index a204d5cb8f71..6973209c4626 100644 --- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp +++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp @@ -215,7 +215,7 @@ static void DrawSpotShadowGeneral(SkCanvas* canvas, const Shape& shape, float ca static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue, SkScalar scaleFactor, SkCanvas* canvas) { - SkASSERT(cornerRadius >= 0.0f); + SkASSERT(casterCornerRadius >= 0.0f); // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space const SkScalar minRadius = 0.5f / scaleFactor; @@ -387,7 +387,7 @@ static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadi static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor, const SkRRect& clipRR, SkCanvas* canvas) { - SkASSERT(cornerRadius >= 0.0f); + SkASSERT(casterCornerRadius >= 0.0f); const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()), SkScalarHalf(casterRect.height())); 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/SkiaLayer.h b/libs/hwui/pipeline/skia/SkiaLayer.h index 0988d7eda89d..904d57e073ca 100644 --- a/libs/hwui/pipeline/skia/SkiaLayer.h +++ b/libs/hwui/pipeline/skia/SkiaLayer.h @@ -30,6 +30,7 @@ struct SkiaLayer { sk_sp<SkSurface> layerSurface; Matrix4 inverseTransformInWindow; + bool hasRenderedSinceRepaint = false; }; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index ca7ee8b7078e..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" @@ -95,6 +95,11 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, profileCanvas->flush(); } + // Log memory statistics + if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) { + dumpResourceCacheUsage(); + } + return true; } @@ -116,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 69e603b6c927..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; } @@ -106,6 +108,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) return; } + layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false; layerCanvas->clear(SK_ColorTRANSPARENT); RenderNodeDrawable root(layerNode, layerCanvas, false); @@ -266,6 +269,20 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli canvas->flush(); } +void SkiaPipeline::dumpResourceCacheUsage() const { + int resources, maxResources; + size_t bytes, maxBytes; + mRenderThread.getGrContext()->getResourceCacheUsage(&resources, &bytes); + mRenderThread.getGrContext()->getResourceCacheLimits(&maxResources, &maxBytes); + + SkString log("Resource Cache Usage:\n"); + log.appendf("%8d items out of %d maximum items\n", resources, maxResources); + log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", + bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f))); + + ALOGD("%s", log.c_str()); +} + } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 877a3538254c..c1c8cbef4d70 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -100,7 +100,10 @@ public: mSpotShadowAlpha = lightInfo.spotShadowAlpha; mLightCenter = lightGeometry.center; } + protected: + void dumpResourceCacheUsage() const; + renderthread::RenderThread& mRenderThread; private: diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 21f348892ccb..ca394b2d0b45 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -23,37 +23,43 @@ #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" +#include <SkSurface.h> #include <SkTypes.h> -#include <WindowContextFactory_android.h> -#include <VulkanWindowContext.h> + +#include <GrContext.h> +#include <GrTypes.h> +#include <vk/GrVkTypes.h> #include <android/native_window.h> #include <cutils/properties.h> #include <strings.h> using namespace android::uirenderer::renderthread; -using namespace sk_app; namespace android { namespace uirenderer { namespace skiapipeline { +SkiaVulkanPipeline::SkiaVulkanPipeline(renderthread::RenderThread& thread) + : SkiaPipeline(thread) + , mVkManager(thread.vulkanManager()) {} + MakeCurrentResult SkiaVulkanPipeline::makeCurrent() { - return (mWindowContext != nullptr) ? - MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed; + return MakeCurrentResult::AlreadyCurrent; } Frame SkiaVulkanPipeline::getFrame() { - LOG_ALWAYS_FATAL_IF(mWindowContext == nullptr, "Tried to draw into null vulkan context!"); - mBackbuffer = mWindowContext->getBackbufferSurface(); - if (mBackbuffer.get() == nullptr) { - // try recreating the context? + LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, + "drawRenderNode called on a context with no surface!"); + + SkSurface* backBuffer = mVkManager.getBackbufferSurface(mVkSurface); + if (backBuffer == nullptr) { SkDebugf("failed to get backbuffer"); return Frame(-1, -1, 0); } // TODO: support buffer age if Vulkan API can do it - Frame frame(mBackbuffer->width(), mBackbuffer->height(), 0); + Frame frame(backBuffer->width(), backBuffer->height(), 0); return frame; } @@ -66,21 +72,28 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) { - if (mBackbuffer.get() == nullptr) { + sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface(); + if (backBuffer.get() == nullptr) { return false; } - renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, mBackbuffer); + SkiaPipeline::updateLighting(lightGeometry, lightInfo); + renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer); layerUpdateQueue->clear(); // Draw visual debugging features if (CC_UNLIKELY(Properties::showDirtyRegions || ProfileType::None != Properties::getProfileType())) { - SkCanvas* profileCanvas = mBackbuffer->getCanvas(); + SkCanvas* profileCanvas = backBuffer->getCanvas(); SkiaProfileRenderer profileRenderer(profileCanvas); profiler->draw(profileRenderer); profileCanvas->flush(); } + // Log memory statistics + if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) { + dumpResourceCacheUsage(); + } + return true; } @@ -94,11 +107,9 @@ bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, currentFrameInfo->markSwapBuffers(); if (*requireSwap) { - mWindowContext->swapBuffers(); + mVkManager.swapBuffers(mVkSurface); } - mBackbuffer.reset(); - return *requireSwap; } @@ -108,6 +119,7 @@ bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bi } DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { + mVkManager.initialize(); Layer* layer = new Layer(mRenderThread.renderState(), 0, 0); return new DeferredLayerUpdater(layer); } @@ -116,33 +128,24 @@ void SkiaVulkanPipeline::onStop() { } bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) { - - if (mWindowContext) { - delete mWindowContext; - mWindowContext = nullptr; + if (mVkSurface) { + mVkManager.destroySurface(mVkSurface); + mVkSurface = nullptr; } if (surface) { - DisplayParams displayParams; - mWindowContext = window_context_factory::NewVulkanForAndroid(surface, displayParams); - if (mWindowContext) { - DeviceInfo::initialize(mWindowContext->getGrContext()->caps()->maxRenderTargetSize()); - } + mVkSurface = mVkManager.createSurface(surface); } - - // this doesn't work for if there is more than one CanvasContext available at one time! - mRenderThread.setGrContext(mWindowContext ? mWindowContext->getGrContext() : nullptr); - - return mWindowContext != nullptr; + return mVkSurface != nullptr; } bool SkiaVulkanPipeline::isSurfaceReady() { - return CC_LIKELY(mWindowContext != nullptr) && mWindowContext->isValid(); + return CC_UNLIKELY(mVkSurface != nullptr); } bool SkiaVulkanPipeline::isContextReady() { - return CC_LIKELY(mWindowContext != nullptr); + return CC_LIKELY(mVkManager.hasVkContext()); } void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index cdc869245be3..aab1d7a547c0 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -17,11 +17,7 @@ #pragma once #include "SkiaPipeline.h" -#include <SkSurface.h> - -namespace sk_app { -class WindowContext; -} +#include "renderthread/VulkanManager.h" namespace android { namespace uirenderer { @@ -29,7 +25,7 @@ namespace skiapipeline { class SkiaVulkanPipeline : public SkiaPipeline { public: - SkiaVulkanPipeline(renderthread::RenderThread& thread) : SkiaPipeline(thread) {} + SkiaVulkanPipeline(renderthread::RenderThread& thread); virtual ~SkiaVulkanPipeline() {} renderthread::MakeCurrentResult makeCurrent() override; @@ -53,8 +49,8 @@ public: static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); private: - sk_app::WindowContext* mWindowContext = nullptr; - sk_sp<SkSurface> mBackbuffer; + renderthread::VulkanManager& mVkManager; + renderthread::VulkanSurface* mVkSurface = nullptr; }; } /* namespace skiapipeline */ 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 968834056ae1..e13d0ce6d688 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -17,9 +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> @@ -157,7 +161,8 @@ RenderThread::RenderThread() : Thread(true) , mFrameCallbackTaskPending(false) , mFrameCallbackTask(nullptr) , mRenderState(nullptr) - , mEglManager(nullptr) { + , mEglManager(nullptr) + , mVkManager(nullptr) { Properties::load(); mFrameCallbackTask = new DispatchFrameCallbacks(this); mLooper = new Looper(false); @@ -191,6 +196,31 @@ void RenderThread::initThreadLocals() { mEglManager = new EglManager(*this); mRenderState = new RenderState(*this); mJankTracker = new JankTracker(mDisplayInfo); + 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) { @@ -282,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 d8677e13f60f..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; @@ -46,6 +47,7 @@ class CanvasContext; class DispatchFrameCallbacks; class EglManager; class RenderProxy; +class VulkanManager; class TaskQueue { public: @@ -92,12 +94,15 @@ public: RenderState& renderState() const { return *mRenderState; } EglManager& eglManager() const { return *mEglManager; } JankTracker& jankTracker() { return *mJankTracker; } + Readback& readback(); const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; } GrContext* getGrContext() const { return mGrContext.get(); } void setGrContext(GrContext* cxt) { mGrContext.reset(cxt); } + VulkanManager& vulkanManager() { return *mVkManager; } + protected: virtual bool threadLoop() override; @@ -148,8 +153,10 @@ private: EglManager* mEglManager; JankTracker* mJankTracker = nullptr; + Readback* mReadback = nullptr; sk_sp<GrContext> mGrContext; + VulkanManager* mVkManager; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp new file mode 100644 index 000000000000..4d239bc616d0 --- /dev/null +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -0,0 +1,675 @@ +/* + * 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 "VulkanManager.h" + +#include "DeviceInfo.h" +#include "RenderThread.h" + +#include <GrContext.h> +#include <GrTypes.h> +#include <vk/GrVkTypes.h> + +namespace android { +namespace uirenderer { +namespace renderthread { + +#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F) +#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F) + +VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) { +} + +void VulkanManager::destroy() { + if (!hasVkContext()) return; + + if (VK_NULL_HANDLE != mCommandPool) { + mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr); + mCommandPool = VK_NULL_HANDLE; + } +} + +void VulkanManager::initialize() { + if (hasVkContext()) { return; } + + auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; }; + + mBackendContext.reset(GrVkBackendContext::Create(&mPresentQueueIndex, canPresent)); + + // Get all the addresses of needed vulkan functions + VkInstance instance = mBackendContext->fInstance; + VkDevice device = mBackendContext->fDevice; + GET_PROC(CreateAndroidSurfaceKHR); + GET_PROC(DestroySurfaceKHR); + GET_PROC(GetPhysicalDeviceSurfaceSupportKHR); + GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); + GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR); + GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR); + GET_DEV_PROC(CreateSwapchainKHR); + GET_DEV_PROC(DestroySwapchainKHR); + GET_DEV_PROC(GetSwapchainImagesKHR); + GET_DEV_PROC(AcquireNextImageKHR); + GET_DEV_PROC(QueuePresentKHR); + GET_DEV_PROC(CreateCommandPool); + GET_DEV_PROC(DestroyCommandPool); + GET_DEV_PROC(AllocateCommandBuffers); + GET_DEV_PROC(FreeCommandBuffers); + GET_DEV_PROC(ResetCommandBuffer); + GET_DEV_PROC(BeginCommandBuffer); + GET_DEV_PROC(EndCommandBuffer); + GET_DEV_PROC(CmdPipelineBarrier); + GET_DEV_PROC(GetDeviceQueue); + GET_DEV_PROC(QueueSubmit); + GET_DEV_PROC(QueueWaitIdle); + GET_DEV_PROC(DeviceWaitIdle); + GET_DEV_PROC(CreateSemaphore); + GET_DEV_PROC(DestroySemaphore); + GET_DEV_PROC(CreateFence); + GET_DEV_PROC(DestroyFence); + GET_DEV_PROC(WaitForFences); + GET_DEV_PROC(ResetFences); + + // create the command pool for the command buffers + if (VK_NULL_HANDLE == mCommandPool) { + VkCommandPoolCreateInfo commandPoolInfo; + memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo)); + commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + // this needs to be on the render queue + commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex; + commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, + &commandPoolInfo, nullptr, &mCommandPool); + SkASSERT(VK_SUCCESS == res); + } + + mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue); + + mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend, + (GrBackendContext) mBackendContext.get())); + DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize()); +} + +// Returns the next BackbufferInfo to use for the next draw. The function will make sure all +// previous uses have finished before returning. +VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) { + SkASSERT(surface->mBackbuffers); + + ++surface->mCurrentBackbufferIndex; + if (surface->mCurrentBackbufferIndex > surface->mImageCount) { + surface->mCurrentBackbufferIndex = 0; + } + + VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + + surface->mCurrentBackbufferIndex; + + // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely + // reuse its commands buffers. + VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, + true, UINT64_MAX); + if (res != VK_SUCCESS) { + return nullptr; + } + + return backbuffer; +} + + +SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { + VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface); + SkASSERT(backbuffer); + + VkResult res; + + res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences); + SkASSERT(VK_SUCCESS == res); + + // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has + // finished presenting and that it is safe to begin sending new commands to the returned image. + res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX, + backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex); + + if (VK_ERROR_SURFACE_LOST_KHR == res) { + // need to figure out how to create a new vkSurface without the platformData* + // maybe use attach somehow? but need a Window + return nullptr; + } + if (VK_ERROR_OUT_OF_DATE_KHR == res) { + // tear swapchain down and try again + if (!createSwapchain(surface)) { + return nullptr; + } + + // acquire the image + res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX, + backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex); + + if (VK_SUCCESS != res) { + return nullptr; + } + } + + // set up layout transfer from initial to color attachment + VkImageLayout layout = surface->mImageLayouts[backbuffer->mImageIndex]; + SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout); + VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT : + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? + 0 : VK_ACCESS_MEMORY_READ_BIT; + VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkImageMemoryBarrier imageMemoryBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + NULL, // pNext + srcAccessMask, // outputMask + dstAccessMask, // inputMask + layout, // oldLayout + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout + mPresentQueueIndex, // srcQueueFamilyIndex + mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex + surface->mImages[backbuffer->mImageIndex], // image + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange + }; + mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0); + + VkCommandBufferBeginInfo info; + memset(&info, 0, sizeof(VkCommandBufferBeginInfo)); + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.flags = 0; + mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info); + + mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, + 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + + mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]); + + VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + // insert the layout transfer into the queue and wait on the acquire + VkSubmitInfo submitInfo; + memset(&submitInfo, 0, sizeof(VkSubmitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 1; + // Wait to make sure aquire semaphore set above has signaled. + submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore; + submitInfo.pWaitDstStageMask = &waitDstStageFlags; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0]; + submitInfo.signalSemaphoreCount = 0; + + // Attach first fence to submission here so we can track when the command buffer finishes. + mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]); + + // We need to notify Skia that we changed the layout of the wrapped VkImage + GrVkImageInfo* imageInfo; + sk_sp<SkSurface> skSurface = surface->mSurfaces[backbuffer->mImageIndex]; + skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo, + SkSurface::kFlushRead_BackendHandleAccess); + imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + surface->mBackbuffer = std::move(skSurface); + return surface->mBackbuffer.get(); +} + +void VulkanManager::destroyBuffers(VulkanSurface* surface) { + if (surface->mBackbuffers) { + for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) { + mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true, + UINT64_MAX); + surface->mBackbuffers[i].mImageIndex = -1; + mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore, + nullptr); + mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore, + nullptr); + mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2, + surface->mBackbuffers[i].mTransitionCmdBuffers); + mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0); + mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0); + } + } + + delete[] surface->mBackbuffers; + surface->mBackbuffers = nullptr; + delete[] surface->mSurfaces; + surface->mSurfaces = nullptr; + delete[] surface->mImageLayouts; + surface->mImageLayouts = nullptr; + delete[] surface->mImages; + surface->mImages = nullptr; +} + +void VulkanManager::destroySurface(VulkanSurface* surface) { + // Make sure all submit commands have finished before starting to destroy objects. + if (VK_NULL_HANDLE != mPresentQueue) { + mQueueWaitIdle(mPresentQueue); + } + mDeviceWaitIdle(mBackendContext->fDevice); + + destroyBuffers(surface); + + if (VK_NULL_HANDLE != surface->mSwapchain) { + mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr); + surface->mSwapchain = VK_NULL_HANDLE; + } + + if (VK_NULL_HANDLE != surface->mVkSurface) { + mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr); + surface->mVkSurface = VK_NULL_HANDLE; + } + delete surface; +} + +void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) { + mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount, + nullptr); + SkASSERT(surface->mImageCount); + surface->mImages = new VkImage[surface->mImageCount]; + mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, + &surface->mImageCount, surface->mImages); + + SkSurfaceProps props(0, kUnknown_SkPixelGeometry); + + bool wantSRGB = VK_FORMAT_R8G8B8A8_SRGB == format; + GrPixelConfig config = wantSRGB ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; + + // set up initial image layouts and create surfaces + surface->mImageLayouts = new VkImageLayout[surface->mImageCount]; + surface->mSurfaces = new sk_sp<SkSurface>[surface->mImageCount]; + for (uint32_t i = 0; i < surface->mImageCount; ++i) { + GrBackendRenderTargetDesc desc; + GrVkImageInfo info; + info.fImage = surface->mImages[i]; + info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 }; + info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; + info.fFormat = format; + info.fLevelCount = 1; + + desc.fWidth = extent.width; + desc.fHeight = extent.height; + desc.fConfig = config; + desc.fOrigin = kTopLeft_GrSurfaceOrigin; + desc.fSampleCnt = 0; + desc.fStencilBits = 0; + desc.fRenderTargetHandle = (GrBackendObject) &info; + + surface->mSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(), + desc, &props); + surface->mImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED; + } + + SkASSERT(mCommandPool != VK_NULL_HANDLE); + + // set up the backbuffers + VkSemaphoreCreateInfo semaphoreInfo; + memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo)); + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreInfo.pNext = nullptr; + semaphoreInfo.flags = 0; + VkCommandBufferAllocateInfo commandBuffersInfo; + memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo)); + commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + commandBuffersInfo.pNext = nullptr; + commandBuffersInfo.commandPool = mCommandPool; + commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + commandBuffersInfo.commandBufferCount = 2; + VkFenceCreateInfo fenceInfo; + memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.pNext = nullptr; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + // we create one additional backbuffer structure here, because we want to + // give the command buffers they contain a chance to finish before we cycle back + surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1]; + for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) { + SkDEBUGCODE(VkResult res); + surface->mBackbuffers[i].mImageIndex = -1; + SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, + &surface->mBackbuffers[i].mAcquireSemaphore); + SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, + &surface->mBackbuffers[i].mRenderSemaphore); + SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo, + surface->mBackbuffers[i].mTransitionCmdBuffers); + SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, + &surface->mBackbuffers[i].mUsageFences[0]); + SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, + &surface->mBackbuffers[i].mUsageFences[1]); + SkASSERT(VK_SUCCESS == res); + } + surface->mCurrentBackbufferIndex = surface->mImageCount; +} + +bool VulkanManager::createSwapchain(VulkanSurface* surface) { + // check for capabilities + VkSurfaceCapabilitiesKHR caps; + VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice, + surface->mVkSurface, &caps); + if (VK_SUCCESS != res) { + return false; + } + + uint32_t surfaceFormatCount; + res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface, + &surfaceFormatCount, nullptr); + if (VK_SUCCESS != res) { + return false; + } + + SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR)); + VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get(); + res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface, + &surfaceFormatCount, surfaceFormats); + if (VK_SUCCESS != res) { + return false; + } + + uint32_t presentModeCount; + res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice, + surface->mVkSurface, &presentModeCount, nullptr); + if (VK_SUCCESS != res) { + return false; + } + + SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR)); + VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get(); + res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice, + surface->mVkSurface, &presentModeCount, presentModes); + if (VK_SUCCESS != res) { + return false; + } + + VkExtent2D extent = caps.currentExtent; + // clamp width; to handle currentExtent of -1 and protect us from broken hints + if (extent.width < caps.minImageExtent.width) { + extent.width = caps.minImageExtent.width; + } + SkASSERT(extent.width <= caps.maxImageExtent.width); + // clamp height + if (extent.height < caps.minImageExtent.height) { + extent.height = caps.minImageExtent.height; + } + SkASSERT(extent.height <= caps.maxImageExtent.height); + + uint32_t imageCount = caps.minImageCount + 2; + if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) { + // Application must settle for fewer images than desired: + imageCount = caps.maxImageCount; + } + + // Currently Skia requires the images to be color attchments and support all transfer + // operations. + VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags); + SkASSERT(caps.supportedTransforms & caps.currentTransform); + SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); + VkCompositeAlphaFlagBitsKHR composite_alpha = + (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + + // Pick our surface format. For now, just make sure it matches our sRGB request: + VkFormat surfaceFormat = VK_FORMAT_UNDEFINED; + VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + + bool wantSRGB = false; +#ifdef ANDROID_ENABLE_LINEAR_BLENDING + wantSRGB = true; +#endif + for (uint32_t i = 0; i < surfaceFormatCount; ++i) { + // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB + VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; + if (desiredFormat == surfaceFormats[i].format) { + surfaceFormat = surfaceFormats[i].format; + colorSpace = surfaceFormats[i].colorSpace; + } + } + + if (VK_FORMAT_UNDEFINED == surfaceFormat) { + return false; + } + + // If mailbox mode is available, use it, as it is the lowest-latency non- + // tearing mode. If not, fall back to FIFO which is always available. + VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; + for (uint32_t i = 0; i < presentModeCount; ++i) { + // use mailbox + if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) { + mode = presentModes[i]; + break; + } + } + + VkSwapchainCreateInfoKHR swapchainCreateInfo; + memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR)); + swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchainCreateInfo.surface = surface->mVkSurface; + swapchainCreateInfo.minImageCount = imageCount; + swapchainCreateInfo.imageFormat = surfaceFormat; + swapchainCreateInfo.imageColorSpace = colorSpace; + swapchainCreateInfo.imageExtent = extent; + swapchainCreateInfo.imageArrayLayers = 1; + swapchainCreateInfo.imageUsage = usageFlags; + + uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex }; + if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) { + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchainCreateInfo.queueFamilyIndexCount = 2; + swapchainCreateInfo.pQueueFamilyIndices = queueFamilies; + } else { + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchainCreateInfo.queueFamilyIndexCount = 0; + swapchainCreateInfo.pQueueFamilyIndices = nullptr; + } + + swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + swapchainCreateInfo.compositeAlpha = composite_alpha; + swapchainCreateInfo.presentMode = mode; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.oldSwapchain = surface->mSwapchain; + + res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr, + &surface->mSwapchain); + if (VK_SUCCESS != res) { + return false; + } + + // destroy the old swapchain + if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { + mDeviceWaitIdle(mBackendContext->fDevice); + + destroyBuffers(surface); + + mDestroySwapchainKHR(mBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr); + } + + createBuffers(surface, surfaceFormat, extent); + + return true; +} + + +VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) { + initialize(); + + if (!window) { + return nullptr; + } + + VulkanSurface* surface = new VulkanSurface(); + + VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; + memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR)); + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + surfaceCreateInfo.pNext = nullptr; + surfaceCreateInfo.flags = 0; + surfaceCreateInfo.window = window; + + VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, + nullptr, &surface->mVkSurface); + if (VK_SUCCESS != res) { + delete surface; + return nullptr; + } + +SkDEBUGCODE( + VkBool32 supported; + res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice, + mPresentQueueIndex, surface->mVkSurface, &supported); + // All physical devices and queue families on Android must be capable of presentation with any + // native window. + SkASSERT(VK_SUCCESS == res && supported); +); + + if (!createSwapchain(surface)) { + destroySurface(surface); + return nullptr; + } + + return surface; +} + +// Helper to know which src stage flags we need to set when transitioning to the present layout +static VkPipelineStageFlags layoutToPipelineStageFlags(const VkImageLayout layout) { + if (VK_IMAGE_LAYOUT_GENERAL == layout) { + return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout || + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) { + return VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout || + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout || + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout || + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) { + return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) { + return VK_PIPELINE_STAGE_HOST_BIT; + } + + SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout); + return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; +} + +// Helper to know which src access mask we need to set when transitioning to the present layout +static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) { + VkAccessFlags flags = 0; + if (VK_IMAGE_LAYOUT_GENERAL == layout) { + flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT; + } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) { + flags = VK_ACCESS_HOST_WRITE_BIT; + } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) { + flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) { + flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) { + flags = VK_ACCESS_TRANSFER_WRITE_BIT; + } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) { + flags = VK_ACCESS_TRANSFER_READ_BIT; + } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) { + flags = VK_ACCESS_SHADER_READ_BIT; + } + return flags; +} + +void VulkanManager::swapBuffers(VulkanSurface* surface) { + VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + + surface->mCurrentBackbufferIndex; + GrVkImageInfo* imageInfo; + SkSurface* skSurface = surface->mSurfaces[backbuffer->mImageIndex].get(); + skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo, + SkSurface::kFlushRead_BackendHandleAccess); + // Check to make sure we never change the actually wrapped image + SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]); + + // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all + // previous work is complete for before presenting. So we first add the necessary barrier here. + VkImageLayout layout = imageInfo->fImageLayout; + VkPipelineStageFlags srcStageMask = layoutToPipelineStageFlags(layout); + VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout); + VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + + VkImageMemoryBarrier imageMemoryBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + NULL, // pNext + srcAccessMask, // outputMask + dstAccessMask, // inputMask + layout, // oldLayout + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout + mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex + mPresentQueueIndex, // dstQueueFamilyIndex + surface->mImages[backbuffer->mImageIndex], // image + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange + }; + + mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0); + VkCommandBufferBeginInfo info; + memset(&info, 0, sizeof(VkCommandBufferBeginInfo)); + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.flags = 0; + mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info); + mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, + 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]); + + surface->mImageLayouts[backbuffer->mImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + // insert the layout transfer into the queue and wait on the acquire + VkSubmitInfo submitInfo; + memset(&submitInfo, 0, sizeof(VkSubmitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitDstStageMask = 0; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1]; + submitInfo.signalSemaphoreCount = 1; + // When this command buffer finishes we will signal this semaphore so that we know it is now + // safe to present the image to the screen. + submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore; + + // Attach second fence to submission here so we can track when the command buffer finishes. + mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]); + + // Submit present operation to present queue. We use a semaphore here to make sure all rendering + // to the image is complete and that the layout has been change to present on the graphics + // queue. + const VkPresentInfoKHR presentInfo = + { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType + NULL, // pNext + 1, // waitSemaphoreCount + &backbuffer->mRenderSemaphore, // pWaitSemaphores + 1, // swapchainCount + &surface->mSwapchain, // pSwapchains + &backbuffer->mImageIndex, // pImageIndices + NULL // pResults + }; + + mQueuePresentKHR(mPresentQueue, &presentInfo); + + surface->mBackbuffer.reset(); +} + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h new file mode 100644 index 000000000000..f0e33206a576 --- /dev/null +++ b/libs/hwui/renderthread/VulkanManager.h @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#ifndef VULKANMANAGER_H +#define VULKANMANAGER_H + +#include <SkSurface.h> +#include <vk/GrVkBackendContext.h> + +#include <vulkan/vulkan.h> + +namespace android { +namespace uirenderer { +namespace renderthread { + +class RenderThread; + +class VulkanSurface { +public: + VulkanSurface() {} + + sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; } + +private: + friend class VulkanManager; + struct BackbufferInfo { + uint32_t mImageIndex; // image this is associated with + VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image + VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done + VkCommandBuffer mTransitionCmdBuffers[2]; // to transition layout between present and render + // We use these fences to make sure the above Command buffers have finished their work + // before attempting to reuse them or destroy them. + VkFence mUsageFences[2]; + }; + + sk_sp<SkSurface> mBackbuffer; + + VkSurfaceKHR mVkSurface = VK_NULL_HANDLE; + VkSwapchainKHR mSwapchain = VK_NULL_HANDLE; + + BackbufferInfo* mBackbuffers; + uint32_t mCurrentBackbufferIndex; + + uint32_t mImageCount; + VkImage* mImages; + VkImageLayout* mImageLayouts; + sk_sp<SkSurface>* mSurfaces; +}; + +// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue, +// which are re-used by CanvasContext. This class is created once and should be used by all vulkan +// windowing contexts. The VulkanManager must be initialized before use. +class VulkanManager { +public: + // Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must + // be call once before use of the VulkanManager. Multiple calls after the first will simiply + // return. + void initialize(); + + // Quick check to see if the VulkanManager has been initialized. + bool hasVkContext() { return mBackendContext.get() != nullptr; } + + // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new + // VulkanSurface object which is returned. + VulkanSurface* createSurface(ANativeWindow* window); + + // Destroy the VulkanSurface and all associated vulkan objects. + void destroySurface(VulkanSurface* surface); + + // Cleans up all the global state in the VulkanManger. + void destroy(); + + // No work is needed to make a VulkanSurface current, and all functions require that a + // VulkanSurface is passed into them so we just return true here. + bool isCurrent(VulkanSurface* surface) { return true; } + + // Returns an SkSurface which wraps the next image returned from vkAcquireNextImageKHR. It also + // will transition the VkImage from a present layout to color attachment so that it can be used + // by the client for drawing. + SkSurface* getBackbufferSurface(VulkanSurface* surface); + + // Presents the current VkImage. + void swapBuffers(VulkanSurface* surface); + +private: + friend class RenderThread; + + explicit VulkanManager(RenderThread& thread); + ~VulkanManager() { destroy(); } + + void destroyBuffers(VulkanSurface* surface); + + bool createSwapchain(VulkanSurface* surface); + void createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent); + + VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface); + + // simple wrapper class that exists only to initialize a pointer to NULL + template <typename FNPTR_TYPE> class VkPtr { + public: + VkPtr() : fPtr(NULL) {} + VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; } + operator FNPTR_TYPE() const { return fPtr; } + private: + FNPTR_TYPE fPtr; + }; + + // WSI interface functions + VkPtr<PFN_vkCreateAndroidSurfaceKHR> mCreateAndroidSurfaceKHR; + VkPtr<PFN_vkDestroySurfaceKHR> mDestroySurfaceKHR; + VkPtr<PFN_vkGetPhysicalDeviceSurfaceSupportKHR> mGetPhysicalDeviceSurfaceSupportKHR; + VkPtr<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR> mGetPhysicalDeviceSurfaceCapabilitiesKHR; + VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> mGetPhysicalDeviceSurfaceFormatsKHR; + VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> mGetPhysicalDeviceSurfacePresentModesKHR; + + VkPtr<PFN_vkCreateSwapchainKHR> mCreateSwapchainKHR; + VkPtr<PFN_vkDestroySwapchainKHR> mDestroySwapchainKHR; + VkPtr<PFN_vkGetSwapchainImagesKHR> mGetSwapchainImagesKHR; + VkPtr<PFN_vkAcquireNextImageKHR> mAcquireNextImageKHR; + VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR; + VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR; + + // Additional vulkan functions + VkPtr<PFN_vkCreateCommandPool> mCreateCommandPool; + VkPtr<PFN_vkDestroyCommandPool> mDestroyCommandPool; + VkPtr<PFN_vkAllocateCommandBuffers> mAllocateCommandBuffers; + VkPtr<PFN_vkFreeCommandBuffers> mFreeCommandBuffers; + VkPtr<PFN_vkResetCommandBuffer> mResetCommandBuffer; + VkPtr<PFN_vkBeginCommandBuffer> mBeginCommandBuffer; + VkPtr<PFN_vkEndCommandBuffer> mEndCommandBuffer; + VkPtr<PFN_vkCmdPipelineBarrier> mCmdPipelineBarrier; + + VkPtr<PFN_vkGetDeviceQueue> mGetDeviceQueue; + VkPtr<PFN_vkQueueSubmit> mQueueSubmit; + VkPtr<PFN_vkQueueWaitIdle> mQueueWaitIdle; + VkPtr<PFN_vkDeviceWaitIdle> mDeviceWaitIdle; + + VkPtr<PFN_vkCreateSemaphore> mCreateSemaphore; + VkPtr<PFN_vkDestroySemaphore> mDestroySemaphore; + VkPtr<PFN_vkCreateFence> mCreateFence; + VkPtr<PFN_vkDestroyFence> mDestroyFence; + VkPtr<PFN_vkWaitForFences> mWaitForFences; + VkPtr<PFN_vkResetFences> mResetFences; + + RenderThread& mRenderThread; + + sk_sp<const GrVkBackendContext> mBackendContext; + uint32_t mPresentQueueIndex; + VkQueue mPresentQueue = VK_NULL_HANDLE; + VkCommandPool mCommandPool = VK_NULL_HANDLE; +}; + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* VULKANMANAGER_H */ + diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp new file mode 100644 index 000000000000..9b0b9507b503 --- /dev/null +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -0,0 +1,73 @@ +/* + * 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" +#include "utils/Color.h" +#include "tests/common/BitmapAllocationTestUtils.h" + +class BitmapShaders; + +static bool _BitmapShaders( + BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>( + "bitmapShader", "Draws bitmap shaders with repeat and mirror modes.")); + +class BitmapShaders : public TestScene { +public: + BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator) + : TestScene() + , mAllocator(allocator) { } + + sp<RenderNode> card; + void createContent(int width, int height, Canvas& canvas) override { + canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver); + sk_sp<Bitmap> hwuiBitmap = mAllocator(200, 200, kRGBA_8888_SkColorType, + [](SkBitmap& skBitmap) { + skBitmap.eraseColor(Color::White); + SkCanvas skCanvas(skBitmap); + SkPaint skPaint; + skPaint.setColor(Color::Red_500); + skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint); + skPaint.setColor(Color::Blue_500); + skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint); + }); + + SkBitmap bitmap; + SkPaint paint; + hwuiBitmap->getSkBitmapForShaders(&bitmap); + + sk_sp<SkShader> repeatShader = SkMakeBitmapShader(bitmap, + SkShader::TileMode::kRepeat_TileMode, + SkShader::TileMode::kRepeat_TileMode, + nullptr, + kNever_SkCopyPixelsMode, + nullptr); + paint.setShader(std::move(repeatShader)); + canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint); + + sk_sp<SkShader> mirrorShader = SkMakeBitmapShader(bitmap, + SkShader::TileMode::kMirror_TileMode, + SkShader::TileMode::kMirror_TileMode, + nullptr, + kNever_SkCopyPixelsMode, + nullptr); + paint.setShader(std::move(mirrorShader)); + canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint); + } + + void doFrame(int frameNr) override { } + + BitmapAllocationTestUtils::BitmapAllocator mAllocator; +};
\ No newline at end of file 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/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index ebc1dd7516c2..1f5622252f6a 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -17,6 +17,7 @@ #include "tests/common/LeakChecker.h" #include "tests/common/TestScene.h" +#include "hwui/Typeface.h" #include "protos/hwui.pb.h" #include "Properties.h" @@ -303,6 +304,8 @@ int main(int argc, char* argv[]) { // set defaults gOpts.count = 150; + Typeface::setRobotoTypefaceForTest(); + parseOptions(argc, argv); if (!gBenchmarkReporter && gOpts.renderOffscreen) { gBenchmarkReporter.reset(new benchmark::ConsoleReporter()); diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index da724a91b0a1..bbaf267a5798 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -182,7 +182,7 @@ void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) { canvas->insertReorderBarrier(true); // Draw child loop - for (int i = 0; i < benchState.range_x(); i++) { + for (int i = 0; i < benchState.range(0); i++) { canvas->drawRenderNode(child.get()); } diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp index d68f5bd05615..398e7a89be1e 100644 --- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp +++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp @@ -113,7 +113,7 @@ static auto SCENES = { void BM_FrameBuilder_defer_scene(benchmark::State& state) { TestUtils::runOnRenderThread([&state](RenderThread& thread) { - const char* sceneName = *(SCENES.begin() + state.range_x()); + const char* sceneName = *(SCENES.begin() + state.range(0)); state.SetLabel(sceneName); auto node = getSyncedSceneNode(sceneName); while (state.KeepRunning()) { @@ -129,7 +129,7 @@ BENCHMARK(BM_FrameBuilder_defer_scene)->DenseRange(0, SCENES.size() - 1); void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) { TestUtils::runOnRenderThread([&state](RenderThread& thread) { - const char* sceneName = *(SCENES.begin() + state.range_x()); + const char* sceneName = *(SCENES.begin() + state.range(0)); state.SetLabel(sceneName); auto node = getSyncedSceneNode(sceneName); diff --git a/libs/hwui/tests/microbench/main.cpp b/libs/hwui/tests/microbench/main.cpp index 9771c85382b4..b5abf5bc5efa 100644 --- a/libs/hwui/tests/microbench/main.cpp +++ b/libs/hwui/tests/microbench/main.cpp @@ -17,6 +17,8 @@ #include "debug/GlesDriver.h" #include "debug/NullGlesDriver.h" +#include "hwui/Typeface.h" + #include <benchmark/benchmark.h> #include <memory> @@ -27,6 +29,7 @@ using namespace android::uirenderer; int main(int argc, char** argv) { debug::GlesDriver::replace(std::make_unique<debug::NullGlesDriver>()); benchmark::Initialize(&argc, argv); + Typeface::setRobotoTypefaceForTest(); benchmark::RunSpecifiedBenchmarks(); return 0; } diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index d05bdbf1709e..cea84c057b63 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -20,6 +20,7 @@ #include "Caches.h" #include "debug/GlesDriver.h" #include "debug/NullGlesDriver.h" +#include "hwui/Typeface.h" #include "thread/TaskManager.h" #include "tests/common/LeakChecker.h" @@ -50,6 +51,13 @@ static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) { raise(sig); } +class TypefaceEnvironment : public testing::Environment { +public: + virtual void SetUp() { + Typeface::setRobotoTypefaceForTest(); + } +}; + int main(int argc, char* argv[]) { // Register a crash handler struct sigaction sa; @@ -69,6 +77,8 @@ int main(int argc, char* argv[]) { testing::InitGoogleTest(&argc, argv); testing::InitGoogleMock(&argc, argv); + testing::AddGlobalTestEnvironment(new TypefaceEnvironment()); + int ret = RUN_ALL_TESTS(); test::LeakChecker::checkForLeaks(); return ret; diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp index fe1ee02420c2..fa3d8bd0930f 100644 --- a/libs/storage/IMountService.cpp +++ b/libs/storage/IMountService.cpp @@ -553,7 +553,7 @@ public: } }; -IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IMountService") +IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IStorageManager") // ---------------------------------------------------------------------- diff --git a/libs/storage/IMountServiceListener.cpp b/libs/storage/IMountServiceListener.cpp index 6a093fd94929..033d70d5694f 100644 --- a/libs/storage/IMountServiceListener.cpp +++ b/libs/storage/IMountServiceListener.cpp @@ -34,7 +34,7 @@ public: const String16& /* oldState */, const String16& /* newState */) { } }; -IMPLEMENT_META_INTERFACE(MountServiceListener, "android.os.storage.IMountServiceListener") +IMPLEMENT_META_INTERFACE(MountServiceListener, "android.os.storage.IStorageEventListener") // ---------------------------------------------------------------------- diff --git a/libs/storage/IMountShutdownObserver.cpp b/libs/storage/IMountShutdownObserver.cpp index 6114d4ac5978..e5de603cd5ee 100644 --- a/libs/storage/IMountShutdownObserver.cpp +++ b/libs/storage/IMountShutdownObserver.cpp @@ -31,7 +31,7 @@ public: virtual void onShutDownComplete(const int32_t /* statusCode */) {} }; -IMPLEMENT_META_INTERFACE(MountShutdownObserver, "android.os.storage.IMountShutdownObserver") +IMPLEMENT_META_INTERFACE(MountShutdownObserver, "android.os.storage.IStorageShutdownObserver") status_t BnMountShutdownObserver::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl index 8870d2a2a420..e86ad1ac5147 100644 --- a/location/java/android/location/IFusedProvider.aidl +++ b/location/java/android/location/IFusedProvider.aidl @@ -22,11 +22,11 @@ import android.hardware.location.IFusedLocationHardware; * Interface definition for Location providers that require FLP services. * @hide */ -interface IFusedProvider { +oneway interface IFusedProvider { /** * Provides access to a FusedLocationHardware instance needed for the provider to work. * * @param instance The FusedLocationHardware available for the provider to use. */ void onFusedLocationHardwareChange(in IFusedLocationHardware instance); -}
\ No newline at end of file +} diff --git a/location/java/android/location/IGeofenceProvider.aidl b/location/java/android/location/IGeofenceProvider.aidl index 5a5fdc635b00..d4ff0dd70bf2 100644 --- a/location/java/android/location/IGeofenceProvider.aidl +++ b/location/java/android/location/IGeofenceProvider.aidl @@ -23,6 +23,6 @@ import android.hardware.location.IGeofenceHardware; * * {@hide} */ -interface IGeofenceProvider { +oneway interface IGeofenceProvider { void setGeofenceHardware(in IGeofenceHardware proxy); } diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 89709ee6b95a..5440f0fc214f 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -584,6 +584,10 @@ public final class AudioAttributes implements Parcelable { * @return the same Builder instance. */ public Builder setLegacyStreamType(int streamType) { + if (streamType == AudioManager.STREAM_ACCESSIBILITY) { + throw new IllegalArgumentException("STREAM_ACCESSIBILITY is not a legacy stream " + + "type that was used for audio playback"); + } return setInternalLegacyStreamType(streamType); } @@ -624,12 +628,15 @@ public final class AudioAttributes implements Parcelable { mContentType = CONTENT_TYPE_SONIFICATION; break; case AudioSystem.STREAM_TTS: + mContentType = CONTENT_TYPE_SONIFICATION; + break; + case AudioSystem.STREAM_ACCESSIBILITY: mContentType = CONTENT_TYPE_SPEECH; break; default: Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes"); } - mUsage = usageForLegacyStreamType(streamType); + mUsage = usageForStreamType(streamType); return this; } @@ -842,8 +849,7 @@ public final class AudioAttributes implements Parcelable { } } - /** @hide */ - public static int usageForLegacyStreamType(int streamType) { + private static int usageForStreamType(int streamType) { switch(streamType) { case AudioSystem.STREAM_VOICE_CALL: return USAGE_VOICE_COMMUNICATION; @@ -862,8 +868,9 @@ public final class AudioAttributes implements Parcelable { return USAGE_VOICE_COMMUNICATION; case AudioSystem.STREAM_DTMF: return USAGE_VOICE_COMMUNICATION_SIGNALLING; - case AudioSystem.STREAM_TTS: + case AudioSystem.STREAM_ACCESSIBILITY: return USAGE_ASSISTANCE_ACCESSIBILITY; + case AudioSystem.STREAM_TTS: default: return USAGE_UNKNOWN; } @@ -915,7 +922,6 @@ public final class AudioAttributes implements Parcelable { switch (aa.getUsage()) { case USAGE_MEDIA: case USAGE_GAME: - case USAGE_ASSISTANCE_ACCESSIBILITY: case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: return AudioSystem.STREAM_MUSIC; case USAGE_ASSISTANCE_SONIFICATION: @@ -935,6 +941,8 @@ public final class AudioAttributes implements Parcelable { case USAGE_NOTIFICATION_COMMUNICATION_DELAYED: case USAGE_NOTIFICATION_EVENT: return AudioSystem.STREAM_NOTIFICATION; + case USAGE_ASSISTANCE_ACCESSIBILITY: + return AudioSystem.STREAM_ACCESSIBILITY; case USAGE_UNKNOWN: return fromGetVolumeControlStream ? AudioManager.USE_DEFAULT_STREAM_TYPE : AudioSystem.STREAM_MUSIC; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f24bf095eb10..435e6ba159e9 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -335,6 +335,9 @@ public class AudioManager { /** @hide Used to identify the volume of audio streams exclusively transmitted through the * speaker (TTS) of the device */ public static final int STREAM_TTS = AudioSystem.STREAM_TTS; + /** Used to identify the volume of audio streams for accessibility prompts */ + public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY; + /** Number of audio streams */ /** * @deprecated Do not iterate on volume stream type values. diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 384be5cb88d0..28c7253f8c76 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -63,13 +63,15 @@ public class AudioSystem /** Used to identify the volume of audio streams exclusively transmitted through the * speaker (TTS) of the device */ public static final int STREAM_TTS = 9; + /** Used to identify the volume of audio streams for accessibility prompts */ + public static final int STREAM_ACCESSIBILITY = 10; /** * @deprecated Use {@link #numStreamTypes() instead} */ public static final int NUM_STREAMS = 5; // Expose only the getter method publicly so we can change it in the future - private static final int NUM_STREAM_TYPES = 10; + private static final int NUM_STREAM_TYPES = 11; public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; } public static final String[] STREAM_NAMES = new String[] { @@ -82,7 +84,8 @@ public class AudioSystem "STREAM_BLUETOOTH_SCO", "STREAM_SYSTEM_ENFORCED", "STREAM_DTMF", - "STREAM_TTS" + "STREAM_TTS", + "STREAM_ACCESSIBILITY" }; /* @@ -773,7 +776,8 @@ public class AudioSystem 7, // STREAM_BLUETOOTH_SCO 7, // STREAM_SYSTEM_ENFORCED 11, // STREAM_DTMF - 11 // STREAM_TTS + 11, // STREAM_TTS + 11, // STREAM_ACCESSIBILITY }; public static String streamToString(int stream) { diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index b5e3af07b7e6..43fb4b9d87a2 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -1513,9 +1513,9 @@ public class AudioTrack extends PlayerBase } @Override - void playerSetVolume(float leftVolume, float rightVolume) { - leftVolume = clampGainOrLevel(leftVolume); - rightVolume = clampGainOrLevel(rightVolume); + void playerSetVolume(boolean muting, float leftVolume, float rightVolume) { + leftVolume = clampGainOrLevel(muting ? 0.0f : leftVolume); + rightVolume = clampGainOrLevel(muting ? 0.0f : rightVolume); native_setVolume(leftVolume, rightVolume); } @@ -2393,8 +2393,8 @@ public class AudioTrack extends PlayerBase } @Override - int playerSetAuxEffectSendLevel(float level) { - level = clampGainOrLevel(level); + int playerSetAuxEffectSendLevel(boolean muting, float level) { + level = clampGainOrLevel(muting ? 0.0f : level); int err = native_setAuxEffectSendLevel(level); return err == 0 ? SUCCESS : ERROR; } 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/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl index 4b1e39f2fc9d..5f6686a88a7e 100644 --- a/media/java/android/media/IRingtonePlayer.aidl +++ b/media/java/android/media/IRingtonePlayer.aidl @@ -26,14 +26,14 @@ import android.os.UserHandle; */ interface IRingtonePlayer { /** Used for Ringtone.java playback */ - void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping); - void stop(IBinder token); + oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping); + oneway void stop(IBinder token); boolean isPlaying(IBinder token); - void setPlaybackProperties(IBinder token, float volume, boolean looping); + oneway void setPlaybackProperties(IBinder token, float volume, boolean looping); /** Used for Notification sound playback. */ - void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa); - void stopAsync(); + oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa); + oneway void stopAsync(); /** Return the title of the media. */ String getTitle(in Uri uri); diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java index 2348ab7c7585..52a68bfd96f9 100644 --- a/media/java/android/media/MediaHTTPService.java +++ b/media/java/android/media/MediaHTTPService.java @@ -17,6 +17,7 @@ package android.media; import android.os.IBinder; +import android.util.Log; /** @hide */ public class MediaHTTPService extends IMediaHTTPService.Stub { @@ -31,10 +32,10 @@ public class MediaHTTPService extends IMediaHTTPService.Stub { /* package private */static IBinder createHttpServiceBinderIfNecessary( String path) { - if (path.startsWith("http://") - || path.startsWith("https://") - || path.startsWith("widevine://")) { + if (path.startsWith("http://") || path.startsWith("https://")) { return (new MediaHTTPService()).asBinder(); + } else if (path.startsWith("widevine://")) { + Log.d(TAG, "Widevine classic is no longer supported"); } return null; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 82cf965a75fb..36ad90b6026c 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1826,8 +1826,8 @@ public class MediaPlayer extends PlayerBase } @Override - void playerSetVolume(float leftVolume, float rightVolume) { - _setVolume(leftVolume, rightVolume); + void playerSetVolume(boolean muting, float leftVolume, float rightVolume) { + _setVolume(muting ? 0.0f : leftVolume, muting ? 0.0f : rightVolume); } private native void _setVolume(float leftVolume, float rightVolume); @@ -1900,8 +1900,8 @@ public class MediaPlayer extends PlayerBase } @Override - int playerSetAuxEffectSendLevel(float level) { - _setAuxEffectSendLevel(level); + int playerSetAuxEffectSendLevel(boolean muting, float level) { + _setAuxEffectSendLevel(muting ? 0.0f : level); return AudioSystem.SUCCESS; } diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index b262d97cfb8e..690a553849e3 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -39,6 +39,11 @@ import com.android.internal.app.IAppOpsService; */ public abstract class PlayerBase { + private final static String TAG = "PlayerBase"; + private static IAudioService sService; //lazy initialization, use getService() + /** Debug app ops */ + protected static final boolean DEBUG_APP_OPS = Log.isLoggable(TAG + ".AO", Log.DEBUG); + // parameters of the player that affect AppOps protected AudioAttributes mAttributes; protected float mLeftVolume = 1.0f; @@ -51,7 +56,6 @@ public abstract class PlayerBase { private boolean mHasAppOpsPlayAudio = true; private final Object mAppOpsLock = new Object(); - /** * Constructor. Must be given audio attributes, as they are required for AppOps. * @param attr non-null audio attributes @@ -101,7 +105,7 @@ public abstract class PlayerBase { void baseStart() { synchronized (mAppOpsLock) { if (isRestricted_sync()) { - playerSetVolume(0, 0); + playerSetVolume(true/*muting*/,0, 0); } } } @@ -114,7 +118,7 @@ public abstract class PlayerBase { return; } } - playerSetVolume(leftVolume, rightVolume); + playerSetVolume(false/*muting*/,leftVolume, rightVolume); } int baseSetAuxEffectSendLevel(float level) { @@ -124,7 +128,7 @@ public abstract class PlayerBase { return AudioSystem.SUCCESS; } } - return playerSetAuxEffectSendLevel(level); + return playerSetAuxEffectSendLevel(false/*muting*/, level); } /** @@ -159,11 +163,18 @@ public abstract class PlayerBase { try { if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) { if (mHasAppOpsPlayAudio) { - playerSetVolume(mLeftVolume, mRightVolume); - playerSetAuxEffectSendLevel(mAuxEffectSendLevel); + if (DEBUG_APP_OPS) { + Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume + + "/" + mRightVolume); + } + playerSetVolume(false/*muting*/, mLeftVolume, mRightVolume); + playerSetAuxEffectSendLevel(false/*muting*/, mAuxEffectSendLevel); } else { - playerSetVolume(0.0f, 0.0f); - playerSetAuxEffectSendLevel(0.0f); + if (DEBUG_APP_OPS) { + Log.v(TAG, "updateAppOpsPlayAudio: muting player"); + } + playerSetVolume(true/*muting*/, 0.0f, 0.0f); + playerSetAuxEffectSendLevel(true/*muting*/, 0.0f); } } } catch (Exception e) { @@ -171,7 +182,6 @@ public abstract class PlayerBase { } } - /** * To be called by the subclass whenever an operation is potentially restricted. * As the media player-common behavior are incorporated into this class, the subclass's need @@ -189,10 +199,41 @@ public abstract class PlayerBase { if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { return false; } + // check force audibility flag and camera restriction + if (((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0) + && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)) { + boolean cameraSoundForced = false; + try { + cameraSoundForced = getService().isCameraSoundForced(); + } catch (RemoteException e) { + Log.e(TAG, "Cannot access AudioService in isRestricted_sync()"); + } catch (NullPointerException e) { + Log.e(TAG, "Null AudioService in isRestricted_sync()"); + } + if (cameraSoundForced) { + return false; + } + } return true; } + private static IAudioService getService() + { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); + sService = IAudioService.Stub.asInterface(b); + return sService; + } + // Abstract methods a subclass needs to implement - abstract void playerSetVolume(float leftVolume, float rightVolume); - abstract int playerSetAuxEffectSendLevel(float level); + /** + * Abstract method for the subclass behavior's for volume and muting commands + * @param muting if true, the player is to be muted, and the volume values can be ignored + * @param leftVolume the left volume to use if muting is false + * @param rightVolume the right volume to use if muting is false + */ + abstract void playerSetVolume(boolean muting, float leftVolume, float rightVolume); + abstract int playerSetAuxEffectSendLevel(boolean muting, float level); } diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index 9fafda48d652..b429e22135be 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -35,9 +35,6 @@ import android.os.ServiceManager; import android.util.AndroidRuntimeException; import android.util.Log; -import com.android.internal.app.IAppOpsCallback; -import com.android.internal.app.IAppOpsService; - /** * The SoundPool class manages and plays audio resources for applications. @@ -111,7 +108,7 @@ import com.android.internal.app.IAppOpsService; * another level, a new SoundPool is created, sounds are loaded, and play * resumes.</p> */ -public class SoundPool { +public class SoundPool extends PlayerBase { static { System.loadLibrary("soundpool"); } // SoundPool messages @@ -130,10 +127,6 @@ public class SoundPool { private final Object mLock; private final AudioAttributes mAttributes; - private final IAppOpsService mAppOps; - private final IAppOpsCallback mAppOpsCallback; - - private static IAudioService sService; /** * Constructor. Constructs a SoundPool object with the following @@ -156,32 +149,14 @@ public class SoundPool { } private SoundPool(int maxStreams, AudioAttributes attributes) { + super(attributes); + // do native setup if (native_setup(new WeakReference<SoundPool>(this), maxStreams, attributes) != 0) { throw new RuntimeException("Native setup failed"); } mLock = new Object(); mAttributes = attributes; - IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); - mAppOps = IAppOpsService.Stub.asInterface(b); - // initialize mHasAppOpsPlayAudio - updateAppOpsPlayAudio(); - // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed - mAppOpsCallback = new IAppOpsCallback.Stub() { - public void opChanged(int op, int uid, String packageName) { - synchronized (mLock) { - if (op == AppOpsManager.OP_PLAY_AUDIO) { - updateAppOpsPlayAudio(); - } - } - } - }; - try { - mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO, - ActivityThread.currentPackageName(), mAppOpsCallback); - } catch (RemoteException e) { - mHasAppOpsPlayAudio = false; - } } /** @@ -192,11 +167,7 @@ public class SoundPool { * should be set to null. */ public final void release() { - try { - mAppOps.stopWatchingMode(mAppOpsCallback); - } catch (RemoteException e) { - // nothing to do here, the SoundPool is being released anyway - } + baseRelease(); native_release(); } @@ -333,9 +304,7 @@ public class SoundPool { */ public final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) { - if (isRestricted()) { - leftVolume = rightVolume = 0; - } + baseStart(); return _play(soundID, leftVolume, rightVolume, priority, loop, rate); } @@ -408,12 +377,26 @@ public class SoundPool { * @param rightVolume right volume value (range = 0.0 to 1.0) */ public final void setVolume(int streamID, float leftVolume, float rightVolume) { - if (isRestricted()) { - return; - } + // unlike other subclasses of PlayerBase, we are not calling + // baseSetVolume(leftVolume, rightVolume) as we need to keep track of each + // volume separately for each player, so we still send the command, but + // handle mute/unmute separately through playerSetVolume() _setVolume(streamID, leftVolume, rightVolume); } + + @Override + void playerSetVolume(boolean muting, float leftVolume, float rightVolume) { + // not used here to control the player volume directly, but used to mute/unmute + _mute(muting); + } + + @Override + int playerSetAuxEffectSendLevel(boolean muting, float level) { + // no aux send functionality so no-op + return AudioSystem.SUCCESS; + } + /** * Similar, except set volume of all channels to same value. * @hide @@ -494,55 +477,6 @@ public class SoundPool { } } - private static IAudioService getService() - { - if (sService != null) { - return sService; - } - IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); - sService = IAudioService.Stub.asInterface(b); - return sService; - } - - private boolean isRestricted() { - // check app ops - if (mHasAppOpsPlayAudio) { - return false; - } - // check bypass flag - if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { - return false; - } - // check force audibility flag and camera restriction - if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0) { -// FIXME: should also check usage when set properly by camera app -// && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) - boolean cameraSoundForced = false; - try { - cameraSoundForced = getService().isCameraSoundForced(); - } catch (RemoteException e) { - Log.e(TAG, "Cannot access AudioService in isRestricted()"); - } catch (NullPointerException e) { - Log.e(TAG, "Null AudioService in isRestricted()"); - } - if (cameraSoundForced) { - return false; - } - } - return true; - } - - private void updateAppOpsPlayAudio() { - try { - final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, - mAttributes.getUsage(), - Process.myUid(), ActivityThread.currentPackageName()); - mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED); - } catch (RemoteException e) { - mHasAppOpsPlayAudio = false; - } - } - private native final int _load(FileDescriptor fd, long offset, long length, int priority); private native final int native_setup(Object weakRef, int maxStreams, @@ -553,6 +487,8 @@ public class SoundPool { private native final void _setVolume(int streamID, float leftVolume, float rightVolume); + private native final void _mute(boolean muting); + // post event from native code to message handler @SuppressWarnings("unchecked") private static void postEventFromNative(Object ref, int msg, int arg1, int arg2, Object obj) { diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 9b217fbd1d24..8d4271f637a2 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -31,6 +31,7 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder \ libmedia \ + libmediadrm \ libskia \ libui \ liblog \ diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index d2dc44045c38..87092d0a5bd1 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -60,6 +60,7 @@ SoundPool::SoundPool(int maxChannels, const audio_attributes_t* pAttributes) ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels); mQuit = false; + mMuted = false; mDecodeThread = 0; memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t)); mAllocated = 0; @@ -366,6 +367,19 @@ void SoundPool::resume(int channelID) } } +void SoundPool::mute(bool muting) +{ + ALOGV("mute(%d)", muting); + Mutex::Autolock lock(&mLock); + mMuted = muting; + if (!mChannels.empty()) { + for (List<SoundChannel*>::iterator iter = mChannels.begin(); + iter != mChannels.end(); ++iter) { + (*iter)->mute(muting); + } + } +} + void SoundPool::autoResume() { ALOGV("autoResume()"); @@ -1032,7 +1046,7 @@ void SoundChannel::setVolume_l(float leftVolume, float rightVolume) { mLeftVolume = leftVolume; mRightVolume = rightVolume; - if (mAudioTrack != NULL) + if (mAudioTrack != NULL && !mMuted) mAudioTrack->setVolume(leftVolume, rightVolume); } @@ -1042,6 +1056,19 @@ void SoundChannel::setVolume(float leftVolume, float rightVolume) setVolume_l(leftVolume, rightVolume); } +void SoundChannel::mute(bool muting) +{ + Mutex::Autolock lock(&mLock); + mMuted = muting; + if (mAudioTrack != NULL) { + if (mMuted) { + mAudioTrack->setVolume(0.0f, 0.0f); + } else { + mAudioTrack->setVolume(mLeftVolume, mRightVolume); + } + } +} + void SoundChannel::setLoop(int loop) { Mutex::Autolock lock(&mLock); diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index aff101f06748..5c48a907c832 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -114,13 +114,14 @@ class SoundChannel : public SoundEvent { public: enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING }; SoundChannel() : mState(IDLE), mNumChannels(1), - mPos(0), mToggle(0), mAutoPaused(false) {} + mPos(0), mToggle(0), mAutoPaused(false), mMuted(false) {} ~SoundChannel(); void init(SoundPool* soundPool); void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume, int priority, int loop, float rate); void setVolume_l(float leftVolume, float rightVolume); void setVolume(float leftVolume, float rightVolume); + void mute(bool muting); void stop_l(); void stop(); void pause(); @@ -154,6 +155,7 @@ private: unsigned long mToggle; bool mAutoPaused; int mPrevSampleID; + bool mMuted; }; // application object for managing a pool of sounds @@ -168,6 +170,7 @@ public: int play(int sampleID, float leftVolume, float rightVolume, int priority, int loop, float rate); void pause(int channelID); + void mute(bool muting); void autoPause(); void resume(int channelID); void autoResume(); @@ -222,6 +225,7 @@ private: int mNextSampleID; int mNextChannelID; bool mQuit; + bool mMuted; // callback Mutex mCallbackLock; diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index ab3e3408bcac..9d0c1f84fada 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -132,6 +132,15 @@ android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID, } static void +android_media_SoundPool_mute(JNIEnv *env, jobject thiz, jboolean muting) +{ + ALOGV("android_media_SoundPool_mute(%d)", muting); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->mute(muting == JNI_TRUE); +} + +static void android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID, jint priority) { @@ -270,6 +279,10 @@ static JNINativeMethod gMethods[] = { "(IFF)V", (void *)android_media_SoundPool_setVolume }, + { "_mute", + "(Z)V", + (void *)android_media_SoundPool_mute + }, { "setPriority", "(II)V", (void *)android_media_SoundPool_setPriority diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp index aa756edb0904..3060df253ae1 100644 --- a/media/tests/players/invoke_mock_media_player.cpp +++ b/media/tests/players/invoke_mock_media_player.cpp @@ -82,7 +82,7 @@ class Player: public MediaPlayerBase virtual status_t stop() { return OK; } virtual status_t pause() { return OK; } virtual bool isPlaying() { return true; } - virtual status_t seekTo(int /* msec */, bool /* precise */) { return OK; } + virtual status_t seekTo(int /* msec */, android::MediaPlayerSeekMode /* mode */) { return OK; } virtual status_t getCurrentPosition(int* /* msec */) { return OK; } virtual status_t getDuration(int* /* msec */) { return OK; } virtual status_t reset() {return OK;} diff --git a/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml b/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml index 440cb647c024..2b69d5bfd540 100644 --- a/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-bn-rBD/strings.xml @@ -24,13 +24,13 @@ <string name="restore_confirm_text" msgid="7499866728030461776">"একটি সংযুক্ত ডেস্কটপ কম্পিউটার থেকে সমস্ত ডেটার সম্পূর্ণ ব্যাকআপ নেওয়ার অনুরোধ করা হয়েছে৷ আপনি কি এটি করার অনুমতি দিতে চান?\n\nযদি আপনি নিজের থেকে এই ব্যাকআপ নেওয়ার অনুরোধ না করে থাকেন, তবে এই প্রক্রিয়াটিতে অনুমতি প্রদান করবেন না৷ এটি বর্তমানে ডিভাইসটিতে থাকা সমস্ত ডেটাকে প্রতিস্থাপন করবে!"</string> <string name="allow_restore_button_label" msgid="3081286752277127827">"আমার ডেটা পুনরুদ্ধার করুন"</string> <string name="deny_restore_button_label" msgid="1724367334453104378">"পুনরুদ্ধার করবেন না"</string> - <string name="current_password_text" msgid="8268189555578298067">"দয়া করে নীচে আপনার বর্তমান ব্যাকআপের পাসওয়ার্ড দিন:"</string> - <string name="device_encryption_restore_text" msgid="1570864916855208992">"দয়া করে নীচে আপনার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷"</string> - <string name="device_encryption_backup_text" msgid="5866590762672844664">"দয়া করে নীচে আপানার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷ এছাড়াও ব্যাকআপ সংরক্ষণাগার এনক্রিপ্ট করতে এটি ব্যবহার করা হবে৷"</string> + <string name="current_password_text" msgid="8268189555578298067">"দয়া করে নিচে আপনার বর্তমান ব্যাকআপের পাসওয়ার্ড দিন:"</string> + <string name="device_encryption_restore_text" msgid="1570864916855208992">"দয়া করে নিচে আপনার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷"</string> + <string name="device_encryption_backup_text" msgid="5866590762672844664">"দয়া করে নিচে আপানার ডিভাইসের এনক্রিপশান পাসওয়ার্ড লিখুন৷ এছাড়াও ব্যাকআপ সংরক্ষণাগার এনক্রিপ্ট করতে এটি ব্যবহার করা হবে৷"</string> <string name="backup_enc_password_text" msgid="4981585714795233099">"সম্পূর্ণ ব্যাকআপ ডেটা এনক্রিপ্ট করতে দয়া করে একটি পাসওয়ার্ড লিখুন৷ যদি এটি খালি রেখে দেওয়া হয় তবে আপনার বর্তমান ব্যাকআপ পাসওয়ার্ডটি ব্যবহার করা হবে:"</string> - <string name="backup_enc_password_optional" msgid="1350137345907579306">"আপনি যদি সম্পূর্ণ ব্যাকআপ ডেটা এনক্রিপ্ট করতে চান তাহলে নীচে একটি পাসওয়ার্ড লিখুন:"</string> - <string name="backup_enc_password_required" msgid="7889652203371654149">"আপনার ডিভাইস এনক্রিপ্ট হয়ে থাকার কারণে আপনার ব্যাকআপকে এনক্রিপ্ট করতে হবে। দয়া করে নীচে একটি পাসওয়ার্ড দিন:"</string> - <string name="restore_enc_password_text" msgid="6140898525580710823">"যদি পুনরুদ্ধার করা ডেটা এনক্রিপ্ট করা থাকে, তবে দয়া করে নীচে পাসওয়ার্ডটি লিখুন:"</string> + <string name="backup_enc_password_optional" msgid="1350137345907579306">"আপনি যদি সম্পূর্ণ ব্যাকআপ ডেটা এনক্রিপ্ট করতে চান তাহলে নিচে একটি পাসওয়ার্ড লিখুন:"</string> + <string name="backup_enc_password_required" msgid="7889652203371654149">"আপনার ডিভাইস এনক্রিপ্ট হয়ে থাকার কারণে আপনার ব্যাকআপকে এনক্রিপ্ট করতে হবে। দয়া করে নিচে একটি পাসওয়ার্ড দিন:"</string> + <string name="restore_enc_password_text" msgid="6140898525580710823">"যদি পুনরুদ্ধার করা ডেটা এনক্রিপ্ট করা থাকে, তবে দয়া করে নিচে পাসওয়ার্ডটি লিখুন:"</string> <string name="toast_backup_started" msgid="550354281452756121">"ব্যাকআপ নেওয়া শুরু হয়েছে..."</string> <string name="toast_backup_ended" msgid="3818080769548726424">"ব্যাকআপ নেওয়া সম্পূর্ণ হয়েছে"</string> <string name="toast_restore_started" msgid="7881679218971277385">"পুনরুদ্ধার করা শুরু হচ্ছে..."</string> diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java index bfc9ff30b5a3..7fa57367301e 100644 --- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java +++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java @@ -27,7 +27,7 @@ import android.os.Handler; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.text.Editable; import android.text.TextWatcher; @@ -64,7 +64,7 @@ public class BackupRestoreConfirmation extends Activity { Handler mHandler; IBackupManager mBackupManager; - IMountService mMountService; + IStorageManager mStorageManager; FullObserver mObserver; int mToken; boolean mIsEncrypted; @@ -158,7 +158,7 @@ public class BackupRestoreConfirmation extends Activity { } mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE)); - mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); + mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); mHandler = new ObserverHandler(getApplicationContext()); final Object oldObserver = getLastNonConfigurationInstance(); @@ -271,14 +271,14 @@ public class BackupRestoreConfirmation extends Activity { boolean deviceIsEncrypted() { try { - return mMountService.getEncryptionState() + return mStorageManager.getEncryptionState() != StorageManager.ENCRYPTION_STATE_NONE - && mMountService.getPasswordType() + && mStorageManager.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT; } catch (Exception e) { - // If we can't talk to the mount service we have a serious problem; fail + // If we can't talk to the storagemanager service we have a serious problem; fail // "secure" i.e. assuming that the device is encrypted. - Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage()); + Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage()); return true; } } diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml index c2ca9989689c..f442219a2ffc 100644 --- a/packages/ExtServices/AndroidManifest.xml +++ b/packages/ExtServices/AndroidManifest.xml @@ -26,16 +26,6 @@ android:directBootAware="true"> <library android:name="android.ext.services"/> - - <service android:name=".notification.Ranker" - android:label="@string/notification_ranker" - android:permission="android.permission.BIND_NOTIFICATION_RANKER_SERVICE" - android:exported="true"> - <intent-filter> - <action android:name="android.service.notification.NotificationRankerService" /> - </intent-filter> - </service> - </application> </manifest> diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml index b77ff1055cb1..531e5171dec8 100644 --- a/packages/ExtServices/res/values/strings.xml +++ b/packages/ExtServices/res/values/strings.xml @@ -16,6 +16,4 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name">Android Services Library</string> - <string name="notification_ranker">Android Notification Ranking Service</string> - <string name="notification_ranker_autobundle_explanation">Auto-grouping updated by Ranking Service</string> </resources> diff --git a/packages/ExtServices/src/android/ext/services/notification/Ranker.java b/packages/ExtServices/src/android/ext/services/notification/Ranker.java deleted file mode 100644 index 2feb51f7a710..000000000000 --- a/packages/ExtServices/src/android/ext/services/notification/Ranker.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.ext.services.notification; - -import android.os.Bundle; -import android.os.UserHandle; -import android.service.notification.Adjustment; -import android.service.notification.NotificationRankerService; -import android.service.notification.StatusBarNotification; -import android.util.Log; -import android.util.Slog; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; - -import android.ext.services.R; - -/** - * Class that provides an updatable ranker module for the notification manager. - * TODO: delete - */ -public final class Ranker extends NotificationRankerService { - private static final String TAG = "RocketRanker"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - @Override - public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance, - boolean user) { - return null; - } -}
\ No newline at end of file diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 9af20d05459a..8cf375a47ae6 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -20,6 +20,8 @@ import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.UriPermission; +import android.content.pm.ParceledListSlice; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.MatrixCursor; @@ -63,6 +65,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.LinkedList; import java.util.List; +import java.util.Objects; public class ExternalStorageProvider extends DocumentsProvider { private static final String TAG = "ExternalStorage"; @@ -502,6 +505,70 @@ public class ExternalStorageProvider extends DocumentsProvider { return getDocIdForFile(file); } + private Uri getDocumentUri(String path, List<UriPermission> accessUriPermissions) + throws FileNotFoundException { + File doc = new File(path); + + final String docId = getDocIdForFile(doc); + + UriPermission docUriPermission = null; + UriPermission treeUriPermission = null; + for (UriPermission uriPermission : accessUriPermissions) { + final Uri uri = uriPermission.getUri(); + if (AUTHORITY.equals(uri.getAuthority())) { + boolean matchesRequestedDoc = false; + if (DocumentsContract.isTreeUri(uri)) { + final String parentDocId = DocumentsContract.getTreeDocumentId(uri); + File parentFile = getFileForDocId(parentDocId); + if (FileUtils.contains(parentFile, doc)) { + treeUriPermission = uriPermission; + matchesRequestedDoc = true; + } + } else { + final String candidateDocId = DocumentsContract.getDocumentId(uri); + final File candidateDoc = getFileForDocId(candidateDocId); + if (Objects.equals(doc.getAbsolutePath(), candidateDoc.getAbsolutePath())) { + docUriPermission = uriPermission; + matchesRequestedDoc = true; + } + } + + if (matchesRequestedDoc && allowsBothReadAndWrite(uriPermission)) { + // This URI permission provides everything an app can get, no need to + // further check any other granted URI. + break; + } + } + } + + // Full permission URI first. + if (allowsBothReadAndWrite(treeUriPermission)) { + return DocumentsContract.buildDocumentUriUsingTree(treeUriPermission.getUri(), docId); + } + + if (allowsBothReadAndWrite(docUriPermission)) { + return docUriPermission.getUri(); + } + + // Then partial permission URI. + if (treeUriPermission != null) { + return DocumentsContract.buildDocumentUriUsingTree(treeUriPermission.getUri(), docId); + } + + if (docUriPermission != null) { + return docUriPermission.getUri(); + } + + throw new SecurityException("The app is not given any access to the document under path " + + path + " with permissions granted in " + accessUriPermissions); + } + + private static boolean allowsBothReadAndWrite(UriPermission permission) { + return permission != null + && permission.isReadPermission() + && permission.isWritePermission(); + } + @Override public String renameDocument(String docId, String displayName) throws FileNotFoundException { // Since this provider treats renames as generating a completely new @@ -721,6 +788,21 @@ public class ExternalStorageProvider extends DocumentsProvider { } break; } + case "getDocumentId": { + final String path = arg; + final List<UriPermission> accessUriPermissions = + extras.getParcelableArrayList(AUTHORITY + ".extra.uriPermissions"); + + try { + final Bundle out = new Bundle(); + final Uri uri = getDocumentUri(path, accessUriPermissions); + out.putParcelable(DocumentsContract.EXTRA_URI, uri); + return out; + } catch (FileNotFoundException e) { + throw new IllegalStateException("File in " + path + " is not found.", e); + } + + } default: Log.w(TAG, "unknown method passed to call(): " + method); } diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java index 0474df7bd89c..e3ab05d81de7 100644 --- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java +++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java @@ -16,7 +16,7 @@ package com.android.keyguard; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; @@ -34,7 +34,7 @@ import android.view.ViewConfiguration; import android.widget.Button; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.policy.EmergencyAffordanceManager; @@ -171,7 +171,7 @@ public class EmergencyButton extends Button { // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT) mPowerManager.userActivity(SystemClock.uptimeMillis(), true); try { - ActivityManagerNative.getDefault().stopSystemLockTaskMode(); + ActivityManager.getService().stopSystemLockTaskMode(); } catch (RemoteException e) { Slog.w(LOG_TAG, "Failed to stop app pinning"); } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index 66e56e0b47ad..6a2949a5ed9f 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -28,7 +28,6 @@ import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.BatteryManager.EXTRA_STATUS; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.UserSwitchObserver; @@ -459,7 +458,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { try { final int userId; try { - userId = ActivityManagerNative.getDefault().getCurrentUser().id; + userId = ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { Log.e(TAG, "Failed to get current user id: ", e); return; @@ -1088,7 +1087,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); try { - ActivityManagerNative.getDefault().registerUserSwitchObserver( + ActivityManager.getService().registerUserSwitchObserver( new UserSwitchObserver() { @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) { diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java index 3fcc600e67f0..6b2c1eeef694 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java @@ -485,6 +485,24 @@ public class MtpDocumentsProvider extends DocumentsProvider { } } + @Override + public boolean isChildDocument(String parentDocumentId, String documentId) { + try { + Identifier identifier = mDatabase.createIdentifier(documentId); + while (true) { + if (parentDocumentId.equals(identifier.mDocumentId)) { + return true; + } + if (identifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) { + return false; + } + identifier = mDatabase.getParentIdentifier(identifier.mDocumentId); + } + } catch (FileNotFoundException error) { + return false; + } + } + void openDevice(int deviceId) throws IOException { synchronized (mDeviceListLock) { if (mDeviceToolkits.containsKey(deviceId)) { diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java index 194e8c727c7a..ef2e0a58903c 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java @@ -854,6 +854,18 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { assertEquals("19", path.getPath().get(2)); } + public void testIsChildDocument() throws Exception { + setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); + setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") }); + setupHierarchyDocuments("1"); + assertTrue(mProvider.isChildDocument("1", "1")); + assertTrue(mProvider.isChildDocument("1", "14")); + assertTrue(mProvider.isChildDocument("2", "14")); + assertTrue(mProvider.isChildDocument("5", "14")); + assertFalse(mProvider.isChildDocument("3", "14")); + assertFalse(mProvider.isChildDocument("6", "14")); + } + private void setupProvider(int flag) { mDatabase = new MtpDatabase(getContext(), flag); mProvider = new MtpDocumentsProvider(); diff --git a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java index 43cc1d6bfe39..d95af61a27c1 100644 --- a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java +++ b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java @@ -530,7 +530,8 @@ public class PlatformAdapter { private int addSP(String xml) throws IOException, SAXException { WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - return wifiManager.addPasspointManagementObject(xml); + // TODO(b/32883320): use the new API for adding Passpoint configuration. + return 0; } private int modifySP(HomeSP homeSP, Collection<MOData> mods) throws IOException { @@ -540,7 +541,8 @@ public class PlatformAdapter { defMods.add(new PasspointManagementObjectDefinition(mod.getBaseURI(), mod.getURN(), mod.getMOTree().toXml())); } - return wifiManager.modifyPasspointManagementObject(homeSP.getFQDN(), defMods); + // TODO(b/32883320): use the new API to update Passpoint configuration. + return 0; } private void reconnect(Network osuNetwork, int newNwkId) { diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml index a50391fb391f..2450be395279 100644 --- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml +++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml @@ -32,7 +32,7 @@ <string name="template_page_range" msgid="428638530038286328">"Opseg od <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string> <string name="pages_range_example" msgid="8558694453556945172">"npr. 1—5,8,11—13"</string> <string name="print_preview" msgid="8010217796057763343">"Pregled prije štampanja"</string> - <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF preglednik za prikaz"</string> + <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF pregledavač za prikaz"</string> <string name="printing_app_crashed" msgid="854477616686566398">"Aplikacija za štampanje je prestala raditi"</string> <string name="generating_print_job" msgid="3119608742651698916">"Kreiranje zadatka za štampu"</string> <string name="save_as_pdf" msgid="5718454119847596853">"Sačuvaj kao PDF"</string> diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java index 1bebebc6fda0..7b0a291e2259 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java @@ -48,7 +48,7 @@ import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.printspooler.R; import java.text.Collator; diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index 23c6615e4715..4b519171b3eb 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -88,7 +88,7 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.printspooler.R; import com.android.printspooler.model.MutexFileProvider; import com.android.printspooler.model.PrintSpoolerProvider; diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java index 74582f3da203..6f0caa244281 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java @@ -63,7 +63,7 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.printspooler.R; import java.util.ArrayList; diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 295248c81888..34d236bcf619 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index bb500872ff5f..d0abbf983ff5 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 829123c54ab6..0eebcd7cbe68 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml index 483770f34726..c0b776eeb9e8 100644 --- a/packages/SettingsLib/res/values-az-rAZ/strings.xml +++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 5498580a8f15..cbb227138e67 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml index f233db935712..12f103d5b216 100644 --- a/packages/SettingsLib/res/values-be-rBY/strings.xml +++ b/packages/SettingsLib/res/values-be-rBY/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index cd77792305e4..23adb5a2438d 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Помощ и отзиви"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml index a011fcfa3038..09988ed2a932 100644 --- a/packages/SettingsLib/res/values-bn-rBD/strings.xml +++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"সহায়তা ও মতামত"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml index 1df5ec97c2b0..561af9270365 100644 --- a/packages/SettingsLib/res/values-bs-rBA/strings.xml +++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 92e90055e44b..19382ecf6c49 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 8ec531ce3675..5276b3a50af7 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index a65c58f5eea2..0c56b8d9ed09 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 923eca167299..60f373b5791b 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Hilfe & Feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 3c0247d1bd27..032d73daae58 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 8ed7444d10fb..57738e8ff495 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Help & feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 8ed7444d10fb..57738e8ff495 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Help & feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 8ed7444d10fb..57738e8ff495 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Help & feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index cdfbc019347e..e0b5bb78c3a6 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 2a21d2239900..259e7fbc0b23 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml index 644bf59eeeef..7d70efe3d169 100644 --- a/packages/SettingsLib/res/values-et-rEE/strings.xml +++ b/packages/SettingsLib/res/values-et-rEE/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menüü"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml index 2217611ab76e..952fda8d0168 100644 --- a/packages/SettingsLib/res/values-eu-rES/strings.xml +++ b/packages/SettingsLib/res/values-eu-rES/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 88ed7fa0bbfa..e998b6970dc8 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"راهنما و بازخورد"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"منو"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index d26fc051f3dc..bf96b59b9179 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 58aab1d61ebb..e2eb10d6d8f0 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 91bbaf0fb3e9..282ae4aa97e4 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml index b71738294c5f..f4bb7ad2b83a 100644 --- a/packages/SettingsLib/res/values-gl-rES/strings.xml +++ b/packages/SettingsLib/res/values-gl-rES/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml index 560518929309..1cded3d3cfe3 100644 --- a/packages/SettingsLib/res/values-gu-rIN/strings.xml +++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index d579ec4508b9..a2a6e0459bb2 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"सहायता और फ़ीडबैक"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 94229b14c9f1..76f04bdf9dbf 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 34f06e5e3cc2..f5f69168b61f 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml index 9428e17010ee..6dcb74567029 100644 --- a/packages/SettingsLib/res/values-hy-rAM/strings.xml +++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Օգնություն և հետադարձ կապ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Ընտրացանկ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index a382e3782ae5..07241b5bf8e5 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan & masukan"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml index 44517a89f48b..8e8307b8b9e1 100644 --- a/packages/SettingsLib/res/values-is-rIS/strings.xml +++ b/packages/SettingsLib/res/values-is-rIS/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 7a32827b9511..d894ccf6c33e 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 2e85770b898b..2ee38ef9095a 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"עזרה ומשוב"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"תפריט"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 00e323c449d1..8b2d7845935a 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -343,4 +343,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"ヘルプとフィードバック"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"メニュー"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml index 2b9e8cb93941..609cb339059c 100644 --- a/packages/SettingsLib/res/values-ka-rGE/strings.xml +++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml index 0037c11c244b..92d7783e4672 100644 --- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml +++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Анықтама және пікір"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Mәзір"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml index 235ea6aa6d26..46cc6ce04982 100644 --- a/packages/SettingsLib/res/values-km-rKH/strings.xml +++ b/packages/SettingsLib/res/values-km-rKH/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"ជំនួយ និងមតិស្ថាបនា"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"ម៉ឺនុយ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml index d7c8d03c0b3b..cf8f3823d1ed 100644 --- a/packages/SettingsLib/res/values-kn-rIN/strings.xml +++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"ಮೆನು"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 21bbc3f8778e..03c0edf7031d 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"고객센터"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"메뉴"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml index ca716caece02..a2eb86d470df 100644 --- a/packages/SettingsLib/res/values-ky-rKG/strings.xml +++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml index 0108c2c89cf9..41a8eef6b15c 100644 --- a/packages/SettingsLib/res/values-lo-rLA/strings.xml +++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ & ຄຳຕິຊົມ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"ເມນູ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 154864f2bf0f..6930c7abbacf 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index df91cb15d622..77348812cc5c 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml index 42bc33fd71ae..711b949bedad 100644 --- a/packages/SettingsLib/res/values-mk-rMK/strings.xml +++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml index a6017d51d349..8bcbf79dc06f 100644 --- a/packages/SettingsLib/res/values-ml-rIN/strings.xml +++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string> <string name="help_feedback_label" msgid="6815040660801785649">"സഹായവും പ്രതികരണവും"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"മെനു"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml index cb6327a52ec4..4fa377927675 100644 --- a/packages/SettingsLib/res/values-mn-rMN/strings.xml +++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Тусламж, санал хүсэлт"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Цэс"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml index b6adb4fc169b..20f64fe40a28 100644 --- a/packages/SettingsLib/res/values-mr-rIN/strings.xml +++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml index 9886d3e5773b..cf7725495029 100644 --- a/packages/SettingsLib/res/values-ms-rMY/strings.xml +++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan & maklum balas"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml index 935ad4027a9f..9db8348177ca 100644 --- a/packages/SettingsLib/res/values-my-rMM/strings.xml +++ b/packages/SettingsLib/res/values-my-rMM/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"အကူအညီနှင့် အကြံပြုချက်"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"မီနူး"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 18b6f60bc92f..cc4e5678014b 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml index 478e19d831f1..a8a918b549f1 100644 --- a/packages/SettingsLib/res/values-ne-rNP/strings.xml +++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 5dcad7aff896..8bb4579f0b19 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -168,7 +168,7 @@ <string name="wifi_verbose_logging" msgid="4203729756047242344">"Uitgebreide wifi-logregistratie insch."</string> <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Agressieve handover van wifi naar mobiel"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string> - <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele gegevens altijd actief"</string> + <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele data altijd actief"</string> <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string> @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml index b678aac86a9c..f19ba3ea04cd 100644 --- a/packages/SettingsLib/res/values-pa-rIN/strings.xml +++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"ਮਦਦ ਅਤੇ ਪ੍ਰਤੀਕਰਮ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"ਮੀਨੂ"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 77a23f220f95..4db3e6e4fa7b 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 588ca67f2151..7855beb3d1fe 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 763cb70ff483..2c366c6197a9 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 588ca67f2151..7855beb3d1fe 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 6a2122a2de31..5d0b965ad3cc 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 1f192c173abb..d301ce1f6e42 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Справка/отзыв"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml index e415544e5f10..f21793bee3c0 100644 --- a/packages/SettingsLib/res/values-si-rLK/strings.xml +++ b/packages/SettingsLib/res/values-si-rLK/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"උදව් සහ ප්රතිපෝෂණ"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"මෙනුව"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 7e636fe7bd62..b478ecf88c2e 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 78fa3fd07c78..b9da0eb0b7bf 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml index ad4cf61b7349..c17376b232f5 100644 --- a/packages/SettingsLib/res/values-sq-rAL/strings.xml +++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 02eb61534b8d..2cf68a537064 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index a936c3eb610a..975a4aa13571 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 25f79b62d5cb..f14cbdd3de68 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml index 9e9e92cd3206..26401227bdbf 100644 --- a/packages/SettingsLib/res/values-ta-rIN/strings.xml +++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"உதவி & கருத்து"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"மெனு"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml index 27f8e09bd54f..60a4d7220fc8 100644 --- a/packages/SettingsLib/res/values-te-rIN/strings.xml +++ b/packages/SettingsLib/res/values-te-rIN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"సహాయం & అభిప్రాయం"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"మెను"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 600597281b3c..fbb67bc4e960 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"ความช่วยเหลือและความคิดเห็น"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"เมนู"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index e9feded8c087..50c43bb01db3 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Tulong at feedback"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 0e73b7be6c9c..c5ae71c634a5 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 1015e1cf543c..b538545f9b3b 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml index 61dc5abcb387..0b5e8a008b2f 100644 --- a/packages/SettingsLib/res/values-ur-rPK/strings.xml +++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"مدد اور تاثرات"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"مینو"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml index a6f9ab817d18..8d1056a1bca8 100644 --- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml +++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index f09e0e5ea77a..21e5b7575367 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 7268dcd347b8..ba657c6792f3 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"帮助和反馈"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"菜单"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index ac9de7415a74..60f56f13b91d 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -339,6 +339,8 @@ <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string> <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string> <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> - <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見反映"</string> + <string name="help_feedback_label" msgid="6815040660801785649">"說明和意見反映"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index f17b5234afe5..6bb730874b87 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見回饋"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 1fc551fc6195..6714b27bec86 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -341,4 +341,6 @@ <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string> <string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string> + <!-- no translation found for time_zone_gmt (2587097992671450782) --> + <skip /> </resources> 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/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java index 381f903a9701..c3acf0b03ab5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java @@ -35,7 +35,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.net.URISyntaxException; import java.util.Locale; 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 b27aad94b0c1..7e3f67b875e5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java @@ -36,6 +36,11 @@ public final class CategoryKey { public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security"; public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts"; public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system"; + 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 ed411be9c3e4..f3658c38ca35 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java @@ -18,19 +18,24 @@ package com.android.settingslib.drawer; import android.content.ComponentName; 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; import com.android.settingslib.applications.InterestingConfigChanges; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import static java.lang.String.CASE_INSENSITIVE_ORDER; + public class CategoryManager { private static final String TAG = "CategoryManager"; @@ -111,6 +116,8 @@ public class CategoryManager { mCategoryByKeyMap.put(category.key, category); } backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap); + normalizePriority(context, mCategoryByKeyMap); + filterDuplicateTiles(mCategoryByKeyMap); } } @@ -163,4 +170,81 @@ public class CategoryManager { } } } + + /** + * Normalize priority values on tiles across injected from all apps to make sure they don't set + * the same priority value. However internal tiles' priority remains unchanged. + * <p/> + * A list of tiles are considered normalized when their priority value increases in a linear + * scan. + */ + @VisibleForTesting + synchronized void normalizePriority(Context context, + Map<String, DashboardCategory> categoryByKeyMap) { + for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) { + normalizePriorityForExternalTiles(context, categoryEntry.getValue()); + } + } + + /** + * 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) + */ + private synchronized void normalizePriorityForExternalTiles(Context context, + DashboardCategory dashboardCategory) { + final String skipPackageName = context.getPackageName(); + + // Sort tiles based on [package, priority within package] + Collections.sort(dashboardCategory.tiles, (tile1, tile2) -> { + final String package1 = tile1.intent.getComponent().getPackageName(); + final String package2 = tile2.intent.getComponent().getPackageName(); + final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2); + // First sort by package name + if (packageCompare != 0) { + return packageCompare; + } else if (TextUtils.equals(package1, skipPackageName)) { + return 0; + } + // Then sort by priority + return tile1.priority - tile2.priority; + }); + // Update priority for all items so no package define the same priority value. + final int count = dashboardCategory.tiles.size(); + for (int i = 0; i < count; i++) { + final String packageName = + dashboardCategory.tiles.get(i).intent.getComponent().getPackageName(); + if (TextUtils.equals(packageName, skipPackageName)) { + // We skip this tile because it's a intent pointing to our own app. We trust the + // priority is set correctly, so don't normalize. + 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 f93c56607ced..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 @@ -56,9 +56,12 @@ public class CategoryKeyTest { allKeys.add(CategoryKey.CATEGORY_SECURITY); allKeys.add(CategoryKey.CATEGORY_ACCOUNT); 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(11); + 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 380f6226512a..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 @@ -16,7 +16,9 @@ package com.android.settingslib.drawer; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.util.Pair; import com.android.settingslib.TestConfig; @@ -116,4 +118,170 @@ public class CategoryManagerTest { // Old category still exists. assertThat(mCategoryByKeyMap.get(oldCategory).tiles.size()).isEqualTo(1); } + + @Test + public void normalizePriority_singlePackage_shouldReorderBasedOnPriority() { + // Create some fake tiles that are not sorted. + final String testPackage = "com.android.test"; + 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 = 50; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage, "class3")); + tile3.priority = 200; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + // Normalize their priorities + mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(), + mCategoryByKeyMap); + + // Verify they are now sorted. + assertThat(category.tiles.get(0)).isSameAs(tile2); + assertThat(category.tiles.get(1)).isSameAs(tile1); + assertThat(category.tiles.get(2)).isSameAs(tile3); + // Verify their priority is normalized + assertThat(category.tiles.get(0).priority).isEqualTo(0); + assertThat(category.tiles.get(1).priority).isEqualTo(1); + assertThat(category.tiles.get(2).priority).isEqualTo(2); + } + + @Test + public void normalizePriority_multiPackage_shouldReorderBasedOnPackageAndPriority() { + // Create some fake tiles that are not sorted. + final String testPackage1 = "com.android.test1"; + final String testPackage2 = "com.android.test2"; + final DashboardCategory category = new DashboardCategory(); + final Tile tile1 = new Tile(); + tile1.intent = + new Intent().setComponent(new ComponentName(testPackage2, "class1")); + tile1.priority = 100; + final Tile tile2 = new Tile(); + tile2.intent = + new Intent().setComponent(new ComponentName(testPackage1, "class2")); + tile2.priority = 100; + final Tile tile3 = new Tile(); + tile3.intent = + new Intent().setComponent(new ComponentName(testPackage1, "class3")); + tile3.priority = 50; + category.tiles.add(tile1); + category.tiles.add(tile2); + category.tiles.add(tile3); + mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category); + + // Normalize their priorities + mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(), + mCategoryByKeyMap); + + // Verify they are now sorted. + assertThat(category.tiles.get(0)).isSameAs(tile3); + assertThat(category.tiles.get(1)).isSameAs(tile2); + assertThat(category.tiles.get(2)).isSameAs(tile1); + // Verify their priority is normalized + assertThat(category.tiles.get(0).priority).isEqualTo(0); + assertThat(category.tiles.get(1).priority).isEqualTo(1); + assertThat(category.tiles.get(2).priority).isEqualTo(2); + } + + @Test + public void normalizePriority_internalPackageTiles_shouldSkipTileForInternalPackage() { + // Create some fake tiles that are not sorted. + 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); + + // Normalize their priorities + mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(), + mCategoryByKeyMap); + + // Verify the sorting order is not changed + assertThat(category.tiles.get(0)).isSameAs(tile1); + assertThat(category.tiles.get(1)).isSameAs(tile2); + assertThat(category.tiles.get(2)).isSameAs(tile3); + // Verify their priorities are not changed. + assertThat(category.tiles.get(0).priority).isEqualTo(100); + 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/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index dd543a35a579..d784a3a5d731 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -645,7 +645,7 @@ class DatabaseHelper extends SQLiteOpenHelper { if (upgradeVersion == 45) { /* - * New settings for MountService + * New settings for StorageManagerService */ db.beginTransaction(); try { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index bf48e5de1da3..1c517733eb2c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -16,7 +16,7 @@ package com.android.providers.settings; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.app.backup.IBackupManager; import android.content.ContentResolver; @@ -343,7 +343,7 @@ public class SettingsHelper { if (loc == null) return; // Couldn't find the saved locale in this version of the software try { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); Configuration config = am.getConfiguration(); config.locale = loc; // indicate this isn't some passing default - the user wants this remembered diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java index 169b01f66881..461573f81789 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java @@ -16,7 +16,7 @@ package com.android.providers.settings; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.IContentProvider; import android.content.pm.PackageManager; import android.database.Cursor; @@ -190,7 +190,7 @@ final public class SettingsService extends Binder { if (mUser == UserHandle.USER_CURRENT) { try { - mUser = ActivityManagerNative.getDefault().getCurrentUser().id; + mUser = ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { throw new RuntimeException("Failed in IPC", e); } diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk index 2170cc148e8a..935d09b20fe6 100644 --- a/packages/Shell/Android.mk +++ b/packages/Shell/Android.mk @@ -5,6 +5,13 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES += \ + ../../../native/cmds/dumpstate/binder/android/os/IDumpstate.aidl \ + ../../../native/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl \ + ../../../native/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl + +LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder + LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 LOCAL_PACKAGE_NAME := Shell diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 227d0e944e6e..d4c7c7ad8cb1 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -112,6 +112,7 @@ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> + <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" /> <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) --> <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) --> diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml index b33da1993cee..9bef2db637d8 100644 --- a/packages/Shell/res/values-tr/strings.xml +++ b/packages/Shell/res/values-tr/strings.xml @@ -22,7 +22,7 @@ <string name="bugreport_updating_title" msgid="4423539949559634214">"Hata raporuna ayrıntılar ekleniyor"</string> <string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfen bekleyin…"</string> <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Hata raporu kısa süre içinde telefonda görüntülenecektir"</string> - <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hata raporunuzu paylaşmak için hafifçe dokunun"</string> + <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hata raporunuzu paylaşmak için dokunun"</string> <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Hata raporunu ekran görüntüsüz paylaşmak için dokunun veya bitirmek için ekran görüntüsünü bekleyin"</string> <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Hata raporunu ekran görüntüsüz paylaşmak için dokunun veya bitirmek için ekran görüntüsünü bekleyin"</string> <string name="bugreport_confirm" msgid="5917407234515812495">"Hata raporları, sistemin çeşitli günlük dosyalarından veriler içerir. Bu günlükler, hassas olarak kabul ettiğiniz verileri (uygulama kullanımı ve konum verileri gibi) içerebilir. Hata raporlarını yalnızca güvendiğiniz kişiler ve uygulamalarla paylaşın."</string> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 772c344fbfdb..47abd4fc2d22 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -31,6 +31,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.text.NumberFormat; import java.util.ArrayList; @@ -44,7 +45,8 @@ import libcore.io.Streams; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.FastPrintWriter; import com.google.android.collect.Lists; @@ -69,10 +71,16 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.IDumpstate; +import android.os.IDumpstateListener; +import android.os.IDumpstateToken; import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemProperties; import android.os.Vibrator; import android.support.v4.content.FileProvider; @@ -146,10 +154,9 @@ public class BugreportProgressService extends Service { static final String EXTRA_INFO = "android.intent.extra.INFO"; private static final int MSG_SERVICE_COMMAND = 1; - private static final int MSG_POLL = 2; - private static final int MSG_DELAYED_SCREENSHOT = 3; - private static final int MSG_SCREENSHOT_REQUEST = 4; - private static final int MSG_SCREENSHOT_RESPONSE = 5; + private static final int MSG_DELAYED_SCREENSHOT = 2; + private static final int MSG_SCREENSHOT_REQUEST = 3; + private static final int MSG_SCREENSHOT_RESPONSE = 4; // Passed to Message.obtain() when msg.arg2 is not used. private static final int UNUSED_ARG2 = -2; @@ -165,16 +172,9 @@ public class BugreportProgressService extends Service { */ static final int SCREENSHOT_DELAY_SECONDS = 3; - /** Polling frequency, in milliseconds. */ - static final long POLLING_FREQUENCY = 2 * DateUtils.SECOND_IN_MILLIS; - - /** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */ - private static final long INACTIVITY_TIMEOUT = 10 * DateUtils.MINUTE_IN_MILLIS; - - /** System properties used for monitoring progress. */ + // TODO: will be gone once fully migrated to Binder + /** System properties used to communicate with dumpstate progress. */ private static final String DUMPSTATE_PREFIX = "dumpstate."; - private static final String PROGRESS_SUFFIX = ".progress"; - private static final String MAX_SUFFIX = ".max"; private static final String NAME_SUFFIX = ".name"; /** System property (and value) used to stop dumpstate. */ @@ -190,7 +190,7 @@ public class BugreportProgressService extends Service { private static final String SCREENSHOT_DIR = "bugreports"; /** Managed dumpstate processes (keyed by id) */ - private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>(); + private final SparseArray<DumpstateListener> mProcesses = new SparseArray<>(); private Context mContext; private ServiceHandler mMainHandler; @@ -267,14 +267,16 @@ public class BugreportProgressService extends Service { protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final int size = mProcesses.size(); if (size == 0) { - writer.printf("No monitored processes"); + writer.println("No monitored processes"); return; } - writer.printf("Foreground id: %d\n\n", mForegroundId); - writer.printf("Monitored dumpstate processes\n"); - writer.printf("-----------------------------\n"); + writer.print("Foreground id: "); writer.println(mForegroundId); + writer.println("\n"); + writer.println("Monitored dumpstate processes"); + writer.println("-----------------------------"); for (int i = 0; i < size; i++) { - writer.printf("%s\n", mProcesses.valueAt(i)); + writer.print("#"); writer.println(i + 1); + writer.println(mProcesses.valueAt(i).info); } } @@ -288,11 +290,6 @@ public class BugreportProgressService extends Service { @Override public void handleMessage(Message msg) { - if (msg.what == MSG_POLL) { - poll(); - return; - } - if (msg.what == MSG_DELAYED_SCREENSHOT) { takeScreenshot(msg.arg1, msg.arg2); return; @@ -339,7 +336,6 @@ public class BugreportProgressService extends Service { stopSelfWhenDone(); return; } - poll(); break; case INTENT_BUGREPORT_FINISHED: if (id == 0) { @@ -367,15 +363,6 @@ public class BugreportProgressService extends Service { return; } - - private void poll() { - if (pollProgress()) { - // Keep polling... - sendEmptyMessageDelayed(MSG_POLL, POLLING_FREQUENCY); - } else { - Log.i(TAG, "Stopped polling"); - } - } } /** @@ -397,11 +384,12 @@ public class BugreportProgressService extends Service { } private BugreportInfo getInfo(int id) { - final BugreportInfo info = mProcesses.get(id); - if (info == null) { + final DumpstateListener listener = mProcesses.get(id); + if (listener == null) { Log.w(TAG, "Not monitoring process with ID " + id); + return null; } - return info; + return listener.info; } /** @@ -433,9 +421,15 @@ public class BugreportProgressService extends Service { Log.w(TAG, "ID " + id + " already watched"); return true; } - mProcesses.put(info.id, info); - updateProgress(info); - return true; + final DumpstateListener listener = new DumpstateListener(info); + mProcesses.put(info.id, listener); + if (listener.connect()) { + updateProgress(info); + return true; + } else { + Log.w(TAG, "not updating progress because it could not connect to dumpstate"); + return false; + } } /** @@ -504,10 +498,7 @@ public class BugreportProgressService extends Service { .setActions(infoAction, screenshotAction, cancelAction); } - if (DEBUG) { - Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid - + "): " + percentageText); - } + Log.d(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentageText); sendForegroundabledNotification(info.id, builder.build()); } @@ -567,96 +558,11 @@ public class BugreportProgressService extends Service { } /** - * Poll {@link SystemProperties} to get the progress on each monitored process. - * - * @return whether it should keep polling. - */ - private boolean pollProgress() { - final int total = mProcesses.size(); - if (total == 0) { - Log.d(TAG, "No process to poll progress."); - } - int activeProcesses = 0; - for (int i = 0; i < total; i++) { - final BugreportInfo info = mProcesses.valueAt(i); - if (info == null) { - Log.wtf(TAG, "pollProgress(): null info at index " + i + "(ID = " - + mProcesses.keyAt(i) + ")"); - continue; - } - - final int pid = info.pid; - final int id = info.id; - if (info.finished) { - if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + " (id: " + id + ")"); - continue; - } - activeProcesses++; - final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX; - info.realProgress = SystemProperties.getInt(progressKey, 0); - if (info.realProgress == 0) { - Log.v(TAG, "System property " + progressKey + " is not set yet"); - } - final String maxKey = DUMPSTATE_PREFIX + pid + MAX_SUFFIX; - info.realMax = SystemProperties.getInt(maxKey, info.max); - if (info.realMax <= 0 ) { - Log.w(TAG, "Property " + maxKey + " is not positive: " + info.max); - continue; - } - /* - * Checks whether the progress changed in a way that should be displayed to the user: - * - info.progress / info.max represents the displayed progress - * - info.realProgress / info.realMax represents the real progress - * - since the real progress can decrease, the displayed progress is only updated if it - * increases - * - the displayed progress is capped at a maximum (like 99%) - */ - final int oldPercentage = (CAPPED_MAX * info.progress) / info.max; - int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax; - int max = info.realMax; - int progress = info.realProgress; - - if (newPercentage > CAPPED_PROGRESS) { - progress = newPercentage = CAPPED_PROGRESS; - max = CAPPED_MAX; - } - - if (newPercentage > oldPercentage) { - if (DEBUG) { - if (progress != info.progress) { - Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id + ") from " - + info.progress + " to " + progress); - } - if (max != info.max) { - Log.v(TAG, "Updating max progress for PID " + pid + "(id: " + id + ") from " - + info.max + " to " + max); - } - } - info.progress = progress; - info.max = max; - info.lastUpdate = System.currentTimeMillis(); - updateProgress(info); - } else { - long inactiveTime = System.currentTimeMillis() - info.lastUpdate; - if (inactiveTime >= INACTIVITY_TIMEOUT) { - Log.w(TAG, "No progress update for PID " + pid + " since " - + info.getFormattedLastUpdate()); - stopProgress(info.id); - } - } - } - if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses); - return activeProcesses > 0; - } - - /** * Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can * change its values. */ private void launchBugreportInfoDialog(int id) { MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS); - // Copy values so it doesn't lock mProcesses while UI is being updated - final String name, title, description; final BugreportInfo info = getInfo(id); if (info == null) { // Most likely am killed Shell before user tapped the notification. Since system might @@ -737,7 +643,7 @@ public class BugreportProgressService extends Service { synchronized (BugreportProgressService.this) { mTakingScreenshot = flag; for (int i = 0; i < mProcesses.size(); i++) { - final BugreportInfo info = mProcesses.valueAt(i); + final BugreportInfo info = mProcesses.valueAt(i).info; if (info.finished) { Log.d(TAG, "Not updating progress for " + info.id + " while taking screenshot" + " because share notification was already sent"); @@ -809,7 +715,7 @@ public class BugreportProgressService extends Service { final int total = mProcesses.size(); if (total > 0) { for (int i = 0; i < total; i++) { - final BugreportInfo info = mProcesses.valueAt(i); + final BugreportInfo info = mProcesses.valueAt(i).info; if (!info.finished) { updateProgress(info); break; @@ -848,13 +754,13 @@ public class BugreportProgressService extends Service { Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent); return; } - mInfoDialog.onBugreportFinished(id); + mInfoDialog.onBugreportFinished(); BugreportInfo info = getInfo(id); if (info == null) { // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first. Log.v(TAG, "Creating info for untracked ID " + id); info = new BugreportInfo(mContext, id); - mProcesses.put(id, info); + mProcesses.put(id, new DumpstateListener(info)); } info.renameScreenshots(mScreenshotsDir); info.bugreportFile = bugreportFile; @@ -1363,7 +1269,6 @@ public class BugreportProgressService extends Service { if (bitmap == null) { return false; } - boolean status; try (final FileOutputStream fos = new FileOutputStream(path)) { if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) { ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150); @@ -1570,7 +1475,7 @@ public class BugreportProgressService extends Service { * <p>Once the bugreport is finished dumpstate has already generated the final files, so * changing the name would have no effect. */ - void onBugreportFinished(int id) { + void onBugreportFinished() { if (mInfoName != null) { mInfoName.setEnabled(false); mInfoName.setText(mSavedName); @@ -1684,7 +1589,7 @@ public class BugreportProgressService extends Service { this.id = id; this.pid = pid; this.name = name; - this.max = max; + this.max = this.realMax = max; } /** @@ -1750,14 +1655,17 @@ public class BugreportProgressService extends Service { public String toString() { final float percent = ((float) progress * 100 / max); final float realPercent = ((float) realProgress * 100 / realMax); - return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished - + "\n\ttitle: " + title + "\n\tdescription: " + description - + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles + return "\tid: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished + + "\n\ttitle: " + title + + "\n\tdescription: " + description + + "\n\tfile: " + bugreportFile + + "\n\tscreenshots: " + screenshotFiles + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")" - + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + ")" + + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + + ")" + "\n\tlast_update: " + getFormattedLastUpdate() - + "\naddingDetailsToZip: " + addingDetailsToZip - + " addedDetailsToZip: " + addedDetailsToZip; + + "\n\taddingDetailsToZip: " + addingDetailsToZip + " addedDetailsToZip: " + + addedDetailsToZip; } // Parcelable contract @@ -1823,16 +1731,118 @@ public class BugreportProgressService extends Service { return path == null ? null : new File(path); } + @SuppressWarnings("unused") public static final Parcelable.Creator<BugreportInfo> CREATOR = new Parcelable.Creator<BugreportInfo>() { + @Override public BugreportInfo createFromParcel(Parcel source) { return new BugreportInfo(source); } + @Override public BugreportInfo[] newArray(int size) { return new BugreportInfo[size]; } }; } + + private final class DumpstateListener extends IDumpstateListener.Stub + implements DeathRecipient { + + private final BugreportInfo info; + private IDumpstateToken token; + + DumpstateListener(BugreportInfo info) { + this.info = info; + } + + /** + * Connects to the {@code dumpstate} binder to receive updates. + */ + boolean connect() { + if (token != null) { + Log.d(TAG, "connect(): " + info.id + " already connected"); + return true; + } + final IBinder service = ServiceManager.getService("dumpstate"); + if (service == null) { + Log.d(TAG, "dumpstate service not bound yet"); + return true; + } + final IDumpstate dumpstate = IDumpstate.Stub.asInterface(service); + try { + token = dumpstate.setListener("Shell", this); + if (token != null) { + token.asBinder().linkToDeath(this, 0); + } + } catch (Exception e) { + Log.e(TAG, "Could not set dumpstate listener: " + e); + } + return token != null; + } + + @Override + public void binderDied() { + if (!info.finished) { + // TODO: linkToDeath() might be called BEFORE Shell received the + // BUGREPORT_FINISHED broadcast, in which case the statements below + // spam logcat (but are harmless). + // The right, long-term solution is to provide an onFinished() callback + // on IDumpstateListener and call it instead of using a broadcast. + Log.w(TAG, "Dumpstate process died:\n" + info); + stopProgress(info.id); + } + token.asBinder().unlinkToDeath(this, 0); + } + + @Override + public void onProgressUpdated(int progress) throws RemoteException { + /* + * Checks whether the progress changed in a way that should be displayed to the user: + * - info.progress / info.max represents the displayed progress + * - info.realProgress / info.realMax represents the real progress + * - since the real progress can decrease, the displayed progress is only updated if it + * increases + * - the displayed progress is capped at a maximum (like 99%) + */ + info.realProgress = progress; + final int oldPercentage = (CAPPED_MAX * info.progress) / info.max; + int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax; + int max = info.realMax; + + if (newPercentage > CAPPED_PROGRESS) { + progress = newPercentage = CAPPED_PROGRESS; + max = CAPPED_MAX; + } + + if (newPercentage > oldPercentage) { + if (DEBUG) { + if (progress != info.progress) { + Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id + + ") from " + info.progress + " to " + progress); + } + if (max != info.max) { + Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id + + ") from " + info.max + " to " + max); + } + } + info.progress = progress; + info.max = max; + info.lastUpdate = System.currentTimeMillis(); + + updateProgress(info); + } + } + + @Override + public void onMaxProgressUpdated(int maxProgress) throws RemoteException { + Log.d(TAG, "onMaxProgressUpdated: " + maxProgress); + info.realMax = maxProgress; + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("token: "); pw.println(token); + } + } } diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java index f6e558f73459..15ce90fa6418 100644 --- a/packages/Shell/src/com/android/shell/BugreportReceiver.java +++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java @@ -40,8 +40,7 @@ public class BugreportReceiver extends BroadcastReceiver { private static final String TAG = "BugreportReceiver"; /** - * Always keep the newest 8 bugreport files; 4 reports and 4 screenshots are - * roughly 17MB of disk space. + * Always keep the newest 8 bugreport files. */ private static final int MIN_KEEP_COUNT = 8; diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index b4bfb0124455..4e3744a49e5e 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -33,7 +33,6 @@ import static com.android.shell.BugreportProgressService.EXTRA_PID; import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT; import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED; import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED; -import static com.android.shell.BugreportProgressService.POLLING_FREQUENCY; import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS; import static org.junit.Assert.assertEquals; @@ -65,6 +64,7 @@ import libcore.io.Streams; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; @@ -116,7 +116,7 @@ public class BugreportReceiverTest { private static final String TAG = "BugreportReceiverTest"; // Timeout for UI operations, in milliseconds. - private static final int TIMEOUT = (int) POLLING_FREQUENCY * 4; + private static final int TIMEOUT = (int) (5 * DateUtils.SECOND_IN_MILLIS); // Timeout for when waiting for a screenshot to finish. private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10; @@ -209,6 +209,12 @@ public class BugreportReceiverTest { } } + /* + * TODO: this test is incomplete because: + * - the assertProgressNotification() is not really asserting the progress because the + * UI automation API doesn't provide a way to check the notification progress bar value + * - it should use the binder object instead of SystemProperties to update progress + */ @Test public void testProgress() throws Exception { resetProperties(); @@ -227,7 +233,6 @@ public class BugreportReceiverTest { // Make sure progress never goes back... SystemProperties.set(MAX_PROPERTY, "2000"); - sleep(POLLING_FREQUENCY + DateUtils.SECOND_IN_MILLIS); assertProgressNotification(NAME, 95.00f); SystemProperties.set(PROGRESS_PROPERTY, "1000"); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2adb26159622..0b5383acf4d2 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -171,6 +171,8 @@ <!-- shortcut manager --> <uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" /> + <uses-permission android:name="android.permission.MODIFY_THEME_OVERLAY" /> + <application android:name=".SystemUIApplication" android:persistent="true" @@ -285,6 +287,22 @@ </intent-filter> </activity> + <activity android:name=".recents.grid.RecentsGridActivity" + android:label="@string/accessibility_desc_recent_apps" + android:exported="false" + android:launchMode="singleInstance" + android:excludeFromRecents="true" + android:stateNotNeeded="true" + android:resumeWhilePausing="true" + android:screenOrientation="behind" + android:resizeableActivity="true" + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" + android:theme="@style/RecentsTheme.Wallpaper"> + <intent-filter> + <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" /> + </intent-filter> + </activity> + <activity android:name=".recents.tv.RecentsTvActivity" android:label="@string/accessibility_desc_recent_apps" android:exported="false" diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java new file mode 100644 index 000000000000..af55e8b830cc --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.content.Context; +import android.view.View; + +/** + * Interface to deal with lack of multiple inheritance + * + * This interface is designed to be used as a base class for plugin interfaces + * that need fragment methods. Plugins should not extend Fragment directly, so + * plugins that are fragments should be extending PluginFragment, but in SysUI + * these same versions should extend Fragment directly. + * + * Only methods that are on Fragment should be included here. + */ +public interface FragmentBase { + View getView(); + Context getContext(); +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java new file mode 100644 index 000000000000..a9d1fa94cf10 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.annotation.Nullable; +import android.app.Fragment; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.view.LayoutInflater; + +public abstract class PluginFragment extends Fragment implements Plugin { + + private static final String KEY_PLUGIN_PACKAGE = "plugin_package_name"; + private Context mPluginContext; + + @Override + public void onCreate(Context sysuiContext, Context pluginContext) { + mPluginContext = pluginContext; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + Context sysuiContext = getContext(); + Context pluginContext = recreatePluginContext(sysuiContext, savedInstanceState); + onCreate(sysuiContext, pluginContext); + } + if (mPluginContext == null) { + throw new RuntimeException("PluginFragments must call super.onCreate(" + + "Context sysuiContext, Context pluginContext)"); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(KEY_PLUGIN_PACKAGE, getContext().getPackageName()); + } + + private Context recreatePluginContext(Context sysuiContext, Bundle savedInstanceState) { + final String pkg = savedInstanceState.getString(KEY_PLUGIN_PACKAGE); + try { + ApplicationInfo appInfo = sysuiContext.getPackageManager().getApplicationInfo(pkg, 0); + return PluginManager.getInstance(sysuiContext).getContext(appInfo, pkg); + } catch (NameNotFoundException e) { + throw new RuntimeException("Plugin with invalid package? " + pkg, e); + } + } + + @Override + public LayoutInflater getLayoutInflater(Bundle savedInstanceState) { + return super.getLayoutInflater(savedInstanceState).cloneInContext(mPluginContext); + } + + /** + * Should only be called after {@link Plugin#onCreate(Context, Context)}. + */ + @Override + public Context getContext() { + return mPluginContext != null ? mPluginContext : super.getContext(); + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java index c64b18826f5e..62d3ce43474f 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java @@ -158,7 +158,11 @@ public class PluginInstanceManager<T extends Plugin> { case PLUGIN_DISCONNECTED: if (DEBUG) Log.d(TAG, "onPluginDisconnected"); mListener.onPluginDisconnected((T) msg.obj); - ((T) msg.obj).onDestroy(); + if (!(msg.obj instanceof PluginFragment)) { + // Only call onDestroy for plugins that aren't fragments, as fragments + // will get the onDestroy as part of the fragment lifecycle. + ((T) msg.obj).onDestroy(); + } break; default: super.handleMessage(msg); @@ -186,7 +190,11 @@ public class PluginInstanceManager<T extends Plugin> { for (int i = mPlugins.size() - 1; i >= 0; i--) { PluginInfo<T> plugin = mPlugins.get(i); mListener.onPluginDisconnected(plugin.mPlugin); - plugin.mPlugin.onDestroy(); + if (!(plugin.mPlugin instanceof PluginFragment)) { + // Only call onDestroy for plugins that aren't fragments, as fragments + // will get the onDestroy as part of the fragment lifecycle. + plugin.mPlugin.onDestroy(); + } } mPlugins.clear(); handleQueryPlugins(null); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java index 85f2e2ad5e9a..60cf3122966a 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java @@ -18,6 +18,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Build; import android.os.HandlerThread; @@ -26,6 +28,7 @@ import android.os.SystemProperties; import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper; import dalvik.system.PathClassLoader; @@ -163,6 +166,16 @@ public class PluginManager extends BroadcastReceiver { return mParentClassLoader; } + public Context getAllPluginContext(Context context) { + return new PluginContextWrapper(context, + new AllPluginClassLoader(context.getClassLoader())); + } + + public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException { + ClassLoader classLoader = getClassLoader(info.sourceDir, pkg); + return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader); + } + public static PluginManager getInstance(Context context) { if (sInstance == null) { sInstance = new PluginManager(context.getApplicationContext()); @@ -170,6 +183,28 @@ public class PluginManager extends BroadcastReceiver { return sInstance; } + private class AllPluginClassLoader extends ClassLoader { + public AllPluginClassLoader(ClassLoader classLoader) { + super(classLoader); + } + + @Override + public Class<?> loadClass(String s) throws ClassNotFoundException { + try { + return super.loadClass(s); + } catch (ClassNotFoundException e) { + for (ClassLoader classLoader : mClassLoaders.values()) { + try { + return classLoader.loadClass(s); + } catch (ClassNotFoundException e1) { + // Will re-throw e if all fail. + } + } + throw e; + } + } + } + @VisibleForTesting public static class PluginInstanceManagerFactory { public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context, @@ -180,7 +215,6 @@ public class PluginManager extends BroadcastReceiver { } } - // This allows plugins to include any libraries or copied code they want by only including // classes from the plugin library. private static class ClassLoaderFilter extends ClassLoader { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java new file mode 100644 index 000000000000..688df466d244 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.plugins.doze; + +import android.app.PendingIntent; +import android.content.Context; + +import com.android.systemui.plugins.Plugin; + +/** + * Provides a {@link DozeUi}. + */ +public interface DozeProvider extends Plugin { + + String ACTION = "com.android.systemui.action.PLUGIN_DOZE"; + int VERSION = 1; + + /** + * Caution: Even if this is called, the DozeUi provided may still be in use until it transitions + * to DozeState.FINISH + */ + @Override + default void onDestroy() { + } + + /** + * @return the plugin's implementation of DozeUi. + */ + DozeUi provideDozeUi(Context context, DozeMachine machine, WakeLock wakeLock); + + /** + * If true, the plugin allows the default pulse triggers to fire, otherwise they are disabled. + */ + default boolean allowDefaultPulseTriggers() { + return false; + } + + /** + * Ui for use in DozeMachine. + */ + interface DozeUi { + /** Called whenever the DozeMachine state transitions */ + void transitionTo(DozeState oldState, DozeState newState); + } + + /** WakeLock wrapper for testability */ + interface WakeLock { + /** @see android.os.PowerManager.WakeLock#acquire() */ + void acquire(); + /** @see android.os.PowerManager.WakeLock#release() */ + void release(); + /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */ + Runnable wrap(Runnable r); + } + + /** Plugin version of the DozeMachine's state */ + enum DozeState { + /** Default state. Transition to INITIALIZED to get Doze going. */ + UNINITIALIZED, + /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */ + INITIALIZED, + /** Regular doze. Device is asleep and listening for pulse triggers. */ + DOZE, + /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */ + DOZE_AOD, + /** Pulse has been requested. Device is awake and preparing UI */ + DOZE_REQUEST_PULSE, + /** Pulse is showing. Device is awake and showing UI. */ + DOZE_PULSING, + /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */ + DOZE_PULSE_DONE, + /** Doze is done. DozeService is finished. */ + FINISH, + /** WakeUp. */ + WAKE_UP, + } + + /** Plugin interface for the doze machine. */ + interface DozeMachine { + /** Request that the DozeMachine transitions to {@code state} */ + void requestState(DozeState state); + + /** Request that the PendingIntent is sent. */ + void requestSendIntent(PendingIntent intent); + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java index 4947863ee9df..a9874fcf328e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java @@ -25,17 +25,21 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.RelativeLayout; -public abstract class QSContainer extends FrameLayout { +import com.android.systemui.plugins.FragmentBase; + +/** + * Fragment that contains QS in the notification shade. Most of the interface is for + * handling the expand/collapsing of the view interaction. + */ +public interface QS extends FragmentBase { public static final String ACTION = "com.android.systemui.action.PLUGIN_QS"; // This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader // change in incompatible ways. - public static final int VERSION = 3; + public static final int VERSION = 4; - public QSContainer(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } + String TAG = "QS"; public abstract void setPanelView(HeightListener notificationPanelView); public abstract BaseStatusBarHeader getHeader(); diff --git a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml new file mode 100644 index 000000000000..cff770ae049a --- /dev/null +++ b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingTop="24dp" + android:paddingBottom="54dp" + android:orientation="vertical" + android:id="@+id/recents_container" + android:background="#99000000"> + <include layout="@layout/recents_stack_action_button" /> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/recents_view" + android:layout_marginLeft="12dp" + android:layout_marginTop="10dp" + android:layout_marginRight="12dp" + android:gravity="center"> + </FrameLayout> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml index 7af247ef1d2f..9ab8ac6346d3 100644 --- a/packages/SystemUI/res/layout/qs_customize_panel.xml +++ b/packages/SystemUI/res/layout/qs_customize_panel.xml @@ -15,7 +15,7 @@ limitations under the License. --> -<!-- Height is 0 because it will be managed by the QSContainer manually --> +<!-- Height is 0 because it will be managed by the QS manually --> <com.android.systemui.qs.customize.QSCustomizer xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 0339e038ebdf..f09657f9e486 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -39,15 +39,15 @@ android:clipToPadding="false" android:clipChildren="false"> - <com.android.systemui.PluginInflateContainer - android:id="@+id/qs_auto_reinflate_container" + <FrameLayout + android:id="@+id/qs_frame" android:layout="@layout/qs_panel" android:layout_width="@dimen/notification_panel_width" android:layout_height="match_parent" android:layout_gravity="@integer/notification_panel_layout_gravity" android:clipToPadding="false" android:clipChildren="false" - systemui:viewType="com.android.systemui.plugins.qs.QSContainer" /> + systemui:viewType="com.android.systemui.plugins.qs.QS" /> <com.android.systemui.statusbar.stack.NotificationStackScrollLayout android:id="@+id/notification_stack_scroller" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 1131b2aeec06..5294c9c46429 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Wysig volgorde van instellings."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 0dc05e619190..601930a91591 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ዘርጋ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 755438edf0fd..a1a8f8d2d0f2 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -198,13 +198,13 @@ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"تشغيل وضع الطائرة."</string> <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"تم إيقاف وضع الطائرة."</string> <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"تم تشغيل وضع الطائرة."</string> - <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"تم تشغيل الرجاء عدم الإزعاج، الأولوية فقط."</string> - <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"تم تشغيل الرجاء عدم الإزعاج، كتم الصوت تمامًا."</string> - <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"تم تشغيل الرجاء عدم الإزعاج، التنبيهات فقط."</string> + <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"تم تشغيل \"عدم الإزعاج، الأولوية فقط\"."</string> + <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"تم تشغيل \"عدم الإزعاج، كتم الصوت تمامًا\"."</string> + <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"تم تشغيل \"عدم الإزعاج، التنبيهات فقط\"."</string> <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"الرجاء عدم الإزعاج."</string> <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"تم تعطيل \"الرجاء عدم الإزعاج\"."</string> <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"تم تعطيل \"الرجاء عدم الإزعاج\"."</string> - <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"تم تشغيل \"الرجاء عدم الإزعاج\"."</string> + <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"تم تشغيل \"عدم الإزعاج\"."</string> <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"البلوتوث."</string> <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"إيقاف البلوتوث."</string> <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"تشغيل البلوتوث."</string> @@ -656,4 +656,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"تعديل ترتيب الإعدادات."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string> </resources> diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml index 87b4433d9761..1bc9e59e9046 100644 --- a/packages/SystemUI/res/values-az-rAZ/strings.xml +++ b/packages/SystemUI/res/values-az-rAZ/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sıralanmasını redaktə edin."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index e1738900354f..8105d9ea50b2 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string> </resources> diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml index 207e223e8766..83c67d4b81a7 100644 --- a/packages/SystemUI/res/values-be-rBY/strings.xml +++ b/packages/SystemUI/res/values-be-rBY/strings.xml @@ -654,4 +654,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 16c94d7e962a..bf3a6148c973 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Редактиране на подредбата на настройките."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string> </resources> diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml index feaa453ff6a6..bd599bcdb2ab 100644 --- a/packages/SystemUI/res/values-bn-rBD/strings.xml +++ b/packages/SystemUI/res/values-bn-rBD/strings.xml @@ -528,7 +528,7 @@ <string name="keyboard_key_home" msgid="2243500072071305073">"হোম"</string> <string name="keyboard_key_back" msgid="2337450286042721351">"ফিরুন"</string> <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"উপরে"</string> - <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নীচে"</string> + <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"নিচে"</string> <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"বাম"</string> <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"ডান"</string> <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"কেন্দ্র"</string> @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"প্রসারিত করুন"</string> </resources> diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml index f361b936981b..5ba720ccef7a 100644 --- a/packages/SystemUI/res/values-bs-rBA/strings.xml +++ b/packages/SystemUI/res/values-bs-rBA/strings.xml @@ -652,4 +652,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 8bedecd6226d..927e75b12ee2 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edita l\'ordre de la configuració."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 0ff0f936e192..69629a9eb208 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -654,4 +654,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upravit pořadí nastavení."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbalit"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index b1124056c6f9..8e34bd037fc6 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -263,7 +263,7 @@ <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Forstyr ikke"</string> <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string> - <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun Alarmer"</string> + <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun alarmer"</string> <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Total stilhed"</string> <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheder)"</string> @@ -356,7 +356,7 @@ <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Helt lydløs. Denne handling slukker også skærmlæsere."</string> <string name="interruption_level_none" msgid="6000083681244492992">"Total stilhed"</string> <string name="interruption_level_priority" msgid="6426766465363855505">"Kun prioritet"</string> - <string name="interruption_level_alarms" msgid="5226306993448328896">"Kun Alarmer"</string> + <string name="interruption_level_alarms" msgid="5226306993448328896">"Kun alarmer"</string> <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nstilhed"</string> <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string> @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediger rækkefølgen af indstillinger."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Udvid"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 9721362526f9..b3a457d7e326 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Reihenfolge der Einstellungen bearbeiten."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Maximieren"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 276b856b1707..050d7f8ca18e 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index ca2e5b33d523..9aca3cc290e8 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index ca2e5b33d523..9aca3cc290e8 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index ca2e5b33d523..9aca3cc290e8 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 81696f69771e..90c2ca1a8817 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar orden de configuración"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index aa9578aa1978..0a45ac1cae4d 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Cambiar el orden de los ajustes."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Mostrar"</string> </resources> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index ab81af59c821..84fadb2b50d6 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muuda seadete järjestust."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string> </resources> diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml index 36170744b416..d6578a24a0c4 100644 --- a/packages/SystemUI/res/values-eu-rES/strings.xml +++ b/packages/SystemUI/res/values-eu-rES/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editatu ezarpenen ordena."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Zabaldu"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 48f0b954d4fc..e00c5b5fbf5f 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ویرایش ترتیب تنظیمات."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"بزرگ کردن"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 5e1ca4bc7d88..08572fe22ffe 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muokkaa asetusten järjestystä."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 765e0aa92714..830bfa7b6269 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index e66d342bd63e..3b138c2ce244 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string> </resources> diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml index 5ccf4a0bbab3..579335d5ef20 100644 --- a/packages/SystemUI/res/values-gl-rES/strings.xml +++ b/packages/SystemUI/res/values-gl-rES/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir a configuración de <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a orde das opcións de configuración."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string> </resources> diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml index 84f9105d2917..48a6d0fe699b 100644 --- a/packages/SystemUI/res/values-gu-rIN/strings.xml +++ b/packages/SystemUI/res/values-gu-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"વિસ્તૃત કરો"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 89b5a6f3bde2..97f3926c940c 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -342,7 +342,7 @@ <string name="description_target_search" msgid="3091587249776033139">"खोजें"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string> <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए बाएं स्लाइड करें."</string> - <string name="zen_priority_introduction" msgid="3070506961866919502">"आपको आपके द्वारा निर्दिष्ट किए गए अलार्म, रिमाइंडर्स, ईवेंट और कॉलर को छोड़कर अन्य ध्वनियों और कंपनों के द्वारा परेशान नहीं किया जाएगा."</string> + <string name="zen_priority_introduction" msgid="3070506961866919502">"आपको आपके द्वारा निर्दिष्ट किए गए अलार्म, रिमाइंडर्स, इवेंट और कॉलर को छोड़कर अन्य ध्वनियों और कंपनों के द्वारा परेशान नहीं किया जाएगा."</string> <string name="zen_priority_customize_button" msgid="7948043278226955063">"कस्टमाइज़ करें"</string> <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"इससे अलार्म, संगीत, वीडियो और गेम सहित सभी ध्वनियां और कंपन अवरुद्ध हो जाते हैं. आप अभी भी फ़ोन काॅल कर सकेंगे."</string> <string name="zen_silence_introduction" msgid="3137882381093271568">"इससे अलार्म, संगीत, वीडियो और गेम सहित सभी ध्वनियां और कंपन अवरुद्ध हो जाते हैं."</string> @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग का क्रम संपादित करें."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 3c5812f89d1f..7ff63bdac12f 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uređivanje redoslijeda postavki."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index f83ba28f9970..bd0805bf5d2a 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Beállítások sorrendjének szerkesztése."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string> </resources> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index 4ce22e435b15..07966cf1c9d8 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -421,7 +421,7 @@ <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string> <string name="hidden_notifications_title" msgid="7139628534207443290">"Ավելի արագ ստացեք ծանուցումները"</string> <string name="hidden_notifications_text" msgid="2326409389088668981">"Տեսեք դրանք մինչև ապակողպելը"</string> - <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ, շնորհակալություն"</string> + <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ"</string> <string name="hidden_notifications_setup" msgid="41079514801976810">"Կարգավորել"</string> <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string> <string name="volume_zen_end_now" msgid="3179845345429841822">"Ավարտել"</string> @@ -430,7 +430,7 @@ <string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string> <string name="screen_pinning_description" msgid="7238941806855968768">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ կոճակը:"</string> <string name="screen_pinning_positive" msgid="3783985798366751226">"Եղավ"</string> - <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ, շնորհակալություն"</string> + <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ"</string> <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string> <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string> <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Թաքցնել"</string> @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Խմբագրել կարգավորումների հերթականությունը:"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 4efffc565f73..6444ae57bf0c 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit urutan setelan."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Luaskan"</string> </resources> diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml index 4875888ae0c9..7e08a01f752e 100644 --- a/packages/SystemUI/res/values-is-rIS/strings.xml +++ b/packages/SystemUI/res/values-is-rIS/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Breyta röð stillinga."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 98a24248a9ed..8ffb10d2641f 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifica l\'ordine delle impostazioni."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Espandi"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index ce73705cdb63..a6d7983c6096 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -652,4 +652,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"עריכת סדר ההגדרות."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index c45fa4f958d8..6ef9f73a6aa6 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"設定の順序を編集します。"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string> </resources> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index a151b8f292e4..695279da446b 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"პარამეტრების მიმდევრობის რედაქტირება."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string> </resources> diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml index 6c0c967b4ad6..ba71182b8926 100644 --- a/packages/SystemUI/res/values-kk-rKZ/strings.xml +++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Параметрлер тәртібін өзгерту."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string> </resources> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index d3e97ccba0a6..b222555765f5 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"កែលំដាប់ការកំណត់"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string> </resources> diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml index cbd71f9cc2fc..b2a6f27e504b 100644 --- a/packages/SystemUI/res/values-kn-rIN/strings.xml +++ b/packages/SystemUI/res/values-kn-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ಸೆಟ್ಟಿಂಗ್ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ವಿಸ್ತೃತಗೊಳಿಸು"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 3827dba5d8be..cefb57a514b1 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"설정 순서 수정"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string> </resources> diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml index 56c836003017..e013c6b7c383 100644 --- a/packages/SystemUI/res/values-ky-rKG/strings.xml +++ b/packages/SystemUI/res/values-ky-rKG/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Жөндөөлөрдүн иретин өзгөртүү."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string> </resources> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index 47a49da4db60..94e789a1325a 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index c4676fa5c631..5af5979ae904 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -652,4 +652,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Redaguoti nustatymų tvarką."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Išskleisti"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index a8266dddb5b4..503c8c8bd742 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediģēt iestatījumu secību."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string> </resources> diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml index c5e2500e9504..62fc35081cbc 100644 --- a/packages/SystemUI/res/values-mk-rMK/strings.xml +++ b/packages/SystemUI/res/values-mk-rMK/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Уредете го редоследот на поставките."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string> </resources> diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml index a1a3b31f105b..9e7d2f29fd91 100644 --- a/packages/SystemUI/res/values-ml-rIN/strings.xml +++ b/packages/SystemUI/res/values-ml-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string> </resources> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index 9b830589dedd..04fb4c23cc7d 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Тохиргооны дарааллыг өөрчилнө үү."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string> </resources> diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml index 800389080a2a..a21019ad50f7 100644 --- a/packages/SystemUI/res/values-mr-rIN/strings.xml +++ b/packages/SystemUI/res/values-mr-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग्जचा क्रम संपादित करा."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करा"</string> </resources> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 1a1696767973..ce942952ccd0 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit susunan tetapan."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string> </resources> diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml index 17b68029c737..8ab1de0f707e 100644 --- a/packages/SystemUI/res/values-my-rMM/strings.xml +++ b/packages/SystemUI/res/values-my-rMM/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ချဲ့ရန်"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index cb691c511fe7..c6312e1b5697 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Endre rekkefølgen på innstillingene."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Vis"</string> </resources> diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml index 97f5f5e849e6..f87223c4aff8 100644 --- a/packages/SystemUI/res/values-ne-rNP/strings.xml +++ b/packages/SystemUI/res/values-ne-rNP/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत गर्नुहोस्"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 43c577dcf597..29f8875667b6 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -164,8 +164,8 @@ <string name="accessibility_settings_button" msgid="799583911231893380">"Systeeminstellingen."</string> <string name="accessibility_notifications_button" msgid="4498000369779421892">"Meldingen."</string> <string name="accessibility_remove_notification" msgid="3603099514902182350">"Melding wissen"</string> - <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS ingeschakeld."</string> - <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Verbinding maken met GPS."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"gps ingeschakeld."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Verbinding maken met gps."</string> <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter ingeschakeld."</string> <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Belsoftware trilt."</string> <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Belsoftware stil."</string> @@ -235,14 +235,14 @@ <string name="accessibility_brightness" msgid="8003681285547803095">"Helderheid van het scherm"</string> <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G/3G-data zijn onderbroken"</string> <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string> - <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele data zijn onderbroken"</string> <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string> <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string> <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string> - <string name="gps_notification_searching_text" msgid="8574247005642736060">"Zoeken naar GPS"</string> - <string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met GPS"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"Zoeken naar gps"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met gps"</string> <string name="accessibility_location_active" msgid="2427290146138169014">"Locatieverzoeken actief"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle meldingen wissen."</string> <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> @@ -310,7 +310,7 @@ <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string> <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Meldingen"</string> <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Zaklamp"</string> - <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobiele gegevens"</string> + <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobiele data"</string> <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Datagebruik"</string> <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Resterende gegevens"</string> <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Limiet overschreden"</string> @@ -376,7 +376,7 @@ <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Alle apps en gegevens in deze sessie worden verwijderd."</string> <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Verwijderen"</string> <string name="guest_wipe_session_title" msgid="6419439912885956132">"Welkom terug, gast!"</string> - <string name="guest_wipe_session_message" msgid="8476238178270112811">"Wilt u doorgaan met je sessie?"</string> + <string name="guest_wipe_session_message" msgid="8476238178270112811">"Wil je doorgaan met je sessie?"</string> <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Opnieuw starten"</string> <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Ja, doorgaan"</string> <string name="guest_notification_title" msgid="1585278533840603063">"Gastgebruiker"</string> @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string> </resources> diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml index 6ef867434ff5..f25662b745f6 100644 --- a/packages/SystemUI/res/values-pa-rIN/strings.xml +++ b/packages/SystemUI/res/values-pa-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 03e599c9f545..78c61029e57c 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -652,4 +652,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings_car.xml b/packages/SystemUI/res/values-pl/strings_car.xml index d6e02d6c0454..dbb0373e161f 100644 --- a/packages/SystemUI/res/values-pl/strings_car.xml +++ b/packages/SystemUI/res/values-pl/strings_car.xml @@ -20,5 +20,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Jedź bezpiecznie"</string> - <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Uważnie obserwuj warunki na drodze i zawsze przestrzegaj obowiązującego prawa. Wskazówki mogą być niedokładne, niekompletne, niebezpieczne, nieprzydatne lub niezgodne z prawem, mogą też obejmować przekraczanie obszarów administracyjnych. Informacje o firmach również mogą być niedokładne lub niekompletne. Dane nie są podawane w czasie rzeczywistym. Nie ma gwarancji, że dane o lokalizacji są dokładne. Podczas prowadzenia samochodu nie obsługuj urządzenia mobilnego ani nie używaj aplikacji nieprzeznaczonych na Android Auto."</string> + <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Uważnie obserwuj warunki na drodze i zawsze przestrzegaj obowiązującego prawa. Wskazówki mogą być niedokładne, niekompletne, niebezpieczne, nieprzydatne lub niezgodne z prawem, mogą też obejmować przekraczanie obszarów administracyjnych. Informacje o firmach również mogą być niedokładne lub niekompletne. Dane nie są podawane w czasie rzeczywistym. Nie ma gwarancji, że dane o lokalizacji są dokładne. Podczas prowadzenia samochodu nie obsługuj urządzenia mobilnego ani nie używaj aplikacji nieprzeznaczonych na Androida Auto."</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 0ae421d1ca5b..0dbdcb9b05d3 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 6ad19f9f37cc..d037cdacd0c2 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a ordem das definições."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 0ae421d1ca5b..0dbdcb9b05d3 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 70ef6ea72291..e33ebb5a3c78 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -652,4 +652,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editați ordinea setărilor."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Extindeți"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 41ec36777e5f..0fbb0bd3c413 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -654,4 +654,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Изменить порядок быстрых настроек."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Развернуть"</string> </resources> diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml index 8f6553192f2b..c4d23788d7f3 100644 --- a/packages/SystemUI/res/values-si-rLK/strings.xml +++ b/packages/SystemUI/res/values-si-rLK/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"දිග හරින්න"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 276c266d2f39..23daf91fb07b 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -654,4 +654,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upraviť poradie nastavení"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index cda2ac91a892..90985e78b12a 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -654,4 +654,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uredi vrstni red nastavitev."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Razširi"</string> </resources> diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml index 33b2d5b81c14..9616c073aca2 100644 --- a/packages/SystemUI/res/values-sq-rAL/strings.xml +++ b/packages/SystemUI/res/values-sq-rAL/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifiko rendin e cilësimeve."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 11d05b748e71..667c65d4e724 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Измени редослед подешавања."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 46e3f054bd05..0a9501784f10 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ändra ordning på inställningarna."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 43aa36d2b3dd..afc5ee40bcf4 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Badilisha orodha ya mipangilio."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Panua"</string> </resources> diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml index 364173e8e84a..99b84392198f 100644 --- a/packages/SystemUI/res/values-ta-rIN/strings.xml +++ b/packages/SystemUI/res/values-ta-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string> </resources> diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml index c1e55c8f5172..c1aeb09bb582 100644 --- a/packages/SystemUI/res/values-te-rIN/strings.xml +++ b/packages/SystemUI/res/values-te-rIN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్లను తెరవండి."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"సెట్టింగ్ల క్రమాన్ని సవరించండి."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"విస్తరింపజేయి"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index f2b1772c19fd..0c461b41c677 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"แก้ไขลำดับการตั้งค่า"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index f58ed174ff5a..caa9f97af345 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"I-edit ang pagkakasunud-sunod ng mga setting."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index e7b1abb751fb..030c97fef490 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sırasını düzenle."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 886a138717fe..c086fff2a786 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -654,4 +654,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змінити порядок налаштувань."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Розгорнути"</string> </resources> diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml index 31d90e2551e3..ff46ad3d1643 100644 --- a/packages/SystemUI/res/values-ur-rPK/strings.xml +++ b/packages/SystemUI/res/values-ur-rPK/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"پھیلائیں"</string> </resources> diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml index 78ad14837904..f2d266109479 100644 --- a/packages/SystemUI/res/values-uz-rUZ/strings.xml +++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Sozlamalar tartibini o‘zgartirish."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Yoyish"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index ba490552dcbd..48b1e4fb9fd3 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Chỉnh sửa thứ tự cài đặt."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 7a7991f7c45a..94c3af1b9b65 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"修改设置顺序。"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 4f7ffe53479d..5785af922224 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -650,4 +650,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定次序。"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 2de07e3e68bc..6562b3902b95 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定順序。"</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 6be736ad84bc..e3c419b481d9 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -648,4 +648,5 @@ <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string> <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Hlela uhlelo lwezilungiselelo."</string> <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string> + <string name="pip_phone_expand" msgid="5889780005575693909">"Nweba"</string> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 9eea3750a8ec..0f5d37ea3691 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -48,6 +48,12 @@ <!-- Whether or not we show the number in the bar. --> <bool name="config_statusBarShowNumber">false</bool> + <!-- Vibrator pattern for camera gesture launch. --> + <integer-array translatable="false" name="config_cameraLaunchGestureVibePattern"> + <item>0</item> + <item>400</item> + </integer-array> + <!-- How many icons may be shown at once in the system bar. Includes any slots that may be reused for things like IME control. --> <integer name="config_maxNotificationIcons">5</integer> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 37a7e38eb4f9..331d09e4537a 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1698,20 +1698,35 @@ not appear on production builds ever. --> <string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string> - <!-- PIP tap once to break through to the activity. Non-translatable since it should + <!-- PIP tap once to break through to the activity title. Non-translatable since it should not appear on production builds ever. --> <string name="pip_tap_through_title" translatable="false">Tap to interact</string> - <!-- PIP tap once to break through to the activity. Non-translatable since it should + <!-- PIP tap once to break through to the activity description. Non-translatable since it should not appear on production builds ever. --> <string name="pip_tap_through_summary" translatable="false">Tap once to interact with the activity</string> - <!-- PIP snap to closest edge. Non-translatable since it should + <!-- PIP snap to closest edge title. Non-translatable since it should not appear on production builds ever. --> <string name="pip_snap_mode_edge_title" translatable="false">Snap to closest edge</string> - <!-- PIP snap to closest edge. Non-translatable since it should + <!-- PIP snap to closest edge description. Non-translatable since it should not appear on production builds ever. --> <string name="pip_snap_mode_edge_summary" translatable="false">Snap to the closest edge</string> + <!-- PIP allow minimize title. Non-translatable since it should + not appear on production builds ever. --> + <string name="pip_allow_minimize_title" translatable="false">Allow PIP to minimize</string> + + <!-- PIP allow minimize description. Non-translatable since it should + not appear on production builds ever. --> + <string name="pip_allow_minimize_summary" translatable="false">Allow PIP to minimize slightly offscreen</string> + + <!-- Tuner string --> + <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string> + <!-- Tuner string --> + <string name="theme" translatable="false">Theme</string> + <!-- Tuner string --> + <string name="default_theme" translatable="false">Default</string> + </resources> diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml index ce636cdaf4fb..18cb9306b1b6 100644 --- a/packages/SystemUI/res/xml/other_settings.xml +++ b/packages/SystemUI/res/xml/other_settings.xml @@ -23,5 +23,10 @@ android:key="power_notification_controls" android:title="@string/tuner_full_importance_settings" android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/> +e + <com.android.systemui.tuner.ThemePreference + android:key="theme" + android:title="@string/theme" + android:summary="%s" /> -</PreferenceScreen>
\ No newline at end of file +</PreferenceScreen> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index f09d6e9fe052..74d5d6ccf92d 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -149,6 +149,12 @@ android:summary="@string/pip_snap_mode_edge_summary" sysui:defValue="false" /> + <com.android.systemui.tuner.TunerSwitch + android:key="pip_allow_minimize" + android:title="@string/pip_allow_minimize_title" + android:summary="@string/pip_allow_minimize_summary" + sysui:defValue="false" /> + </PreferenceScreen> <PreferenceScreen diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java index e1d6a94fcf07..c4698c39075d 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java @@ -32,8 +32,8 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; -import android.os.Looper; import android.provider.Settings; + import com.android.systemui.statusbar.policy.BatteryController; public class BatteryMeterDrawable extends Drawable implements @@ -182,13 +182,13 @@ public class BatteryMeterDrawable extends Drawable implements mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); updateShowPercent(); - mBatteryController.addStateChangedCallback(this); + mBatteryController.addCallback(this); } public void stopListening() { mListening = false; mContext.getContentResolver().unregisterContentObserver(mSettingObserver); - mBatteryController.removeStateChangedCallback(this); + mBatteryController.removeCallback(this); } public void disableShowPercent() { diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 4f3ffde06294..ef1c25dc2d97 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -17,7 +17,6 @@ package com.android.systemui; import android.content.Context; import android.content.res.TypedArray; -import android.os.Handler; import android.util.ArraySet; import android.util.AttributeSet; import android.view.View; @@ -73,7 +72,7 @@ public class BatteryMeterView extends ImageView implements @Override public void onAttachedToWindow() { super.onAttachedToWindow(); - mBatteryController.addStateChangedCallback(this); + mBatteryController.addCallback(this); mDrawable.startListening(); TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST); } @@ -81,7 +80,7 @@ public class BatteryMeterView extends ImageView implements @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); - mBatteryController.removeStateChangedCallback(this); + mBatteryController.removeCallback(this); mDrawable.stopListening(); TunerService.get(getContext()).removeTunable(this); } diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java index 9a64a41df4ea..3a8536b8127e 100644 --- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java @@ -16,7 +16,7 @@ package com.android.systemui; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -66,7 +66,7 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { UserInfo currentUser; try { - currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + currentUser = ActivityManager.getService().getCurrentUser(); } catch (RemoteException e) { return; } @@ -96,7 +96,7 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); UserInfo currentUser; try { - currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + currentUser = ActivityManager.getService().getCurrentUser(); } catch (RemoteException e) { Log.e(TAG, "Couldn't wipe session because ActivityManager is dead"); return; @@ -122,12 +122,12 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { try { if (newGuest == null) { Log.e(TAG, "Could not create new guest, switching back to system user"); - ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM); + ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM); userManager.removeUser(currentUser.id); WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */); return; } - ActivityManagerNative.getDefault().switchUser(newGuest.id); + ActivityManager.getService().switchUser(newGuest.id); userManager.removeUser(currentUser.id); } catch (RemoteException e) { Log.e(TAG, "Couldn't wipe session because ActivityManager or WindowManager is dead"); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 99e787676ef5..b20798481a58 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -29,9 +29,12 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.util.Log; +import com.android.systemui.doze.DozeFactory; +import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyboard.KeyboardUI; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.media.RingtonePlayer; +import com.android.systemui.pip.PipUI; import com.android.systemui.plugins.OverlayPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; @@ -42,7 +45,6 @@ import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.SystemBars; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.tuner.TunerService; -import com.android.systemui.pip.PipUI; import com.android.systemui.usb.StorageNotification; import com.android.systemui.volume.VolumeUI; @@ -61,6 +63,7 @@ public class SystemUIApplication extends Application { * The classes of the stuff to start. */ private final Class<?>[] SERVICES = new Class[] { + FragmentService.class, TunerService.class, KeyguardViewMediator.class, Recents.class, @@ -74,7 +77,8 @@ public class SystemUIApplication extends Application { PipUI.class, ShortcutKeyDispatcher.class, VendorServices.class, - LatencyTester.class + LatencyTester.class, + DozeFactory.Initializer.class, }; /** diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java index b1f454e5e3d0..965ded5beaff 100644 --- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java +++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java @@ -35,8 +35,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session; -import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent; /** * Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java index b39803a01783..f8b73a172516 100644 --- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java +++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java @@ -22,10 +22,10 @@ import android.view.MotionEvent; import java.util.ArrayList; -import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session; -import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent; -import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent; -import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.SensorEvent; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.TouchEvent; /** * Collects touch, sensor and phone events and converts the data to diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 4cfc811de1a0..5b10756988a4 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -17,19 +17,52 @@ package com.android.systemui.doze; import android.app.Application; +import android.app.PendingIntent; import android.content.Context; import android.hardware.SensorManager; import android.os.Handler; import android.os.PowerManager; +import android.os.SystemClock; import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.systemui.SystemUI; import com.android.systemui.SystemUIApplication; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; +import com.android.systemui.plugins.doze.DozeProvider; import com.android.systemui.statusbar.phone.DozeParameters; public class DozeFactory { + private static DozeFactory sInstance; + + private DozeProvider mDozePlugin; + + /** Returns the singleton instance. */ + public static DozeFactory getInstance(Context context) { + if (sInstance == null) { + sInstance = new DozeFactory(); + PluginManager.getInstance(context).addPluginListener(DozeProvider.ACTION, + new PluginListener<DozeProvider>() { + @Override + public void onPluginConnected(DozeProvider plugin) { + sInstance.mDozePlugin = plugin; + } + + @Override + public void onPluginDisconnected(DozeProvider plugin) { + if (sInstance.mDozePlugin == plugin) { + sInstance.mDozePlugin = null; + } + } + }, + DozeProvider.VERSION, false /* Only one */); + } + return sInstance; + } + /** Creates a DozeMachine with its parts for {@code dozeService}. */ - public static DozeMachine assembleMachine(DozeService dozeService) { + public DozeMachine assembleMachine(DozeService dozeService) { Context context = dozeService; SensorManager sensorManager = context.getSystemService(SensorManager.class); PowerManager powerManager = context.getSystemService(PowerManager.class); @@ -43,14 +76,103 @@ public class DozeFactory { DozeMachine machine = new DozeMachine(dozeService, params, wakeLock); machine.setParts(new DozeMachine.Part[]{ - new DozeTriggers(context, machine, host, config, params, - sensorManager, handler, wakeLock), - new DozeUi(context, machine, wakeLock, host), + createDozeTriggers(context, sensorManager, host, config, params, handler, wakeLock, + machine), + createDozeUi(context, host, wakeLock, machine), }); return machine; } + private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager, + DozeHost host, AmbientDisplayConfiguration config, DozeParameters params, + Handler handler, WakeLock wakeLock, DozeMachine machine) { + boolean allowPulseTriggers = mDozePlugin == null || mDozePlugin.allowDefaultPulseTriggers(); + return new DozeTriggers(context, machine, host, config, params, + sensorManager, handler, wakeLock, allowPulseTriggers); + } + + private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock, + DozeMachine machine) { + if (mDozePlugin != null) { + DozeProvider.DozeUi dozeUi = mDozePlugin.provideDozeUi(context, + pluginMachine(context, machine, host), + wakeLock); + return (oldState, newState) -> { + dozeUi.transitionTo(pluginState(oldState), + pluginState(newState)); + }; + } else { + return new DozeUi(context, machine, wakeLock, host); + } + } + + private DozeProvider.DozeMachine pluginMachine(Context context, DozeMachine machine, + DozeHost host) { + return new DozeProvider.DozeMachine() { + @Override + public void requestState(DozeProvider.DozeState state) { + if (state == DozeProvider.DozeState.WAKE_UP) { + PowerManager pm = context.getSystemService(PowerManager.class); + pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE"); + return; + } + machine.requestState(implState(state)); + } + + @Override + public void requestSendIntent(PendingIntent intent) { + host.startPendingIntentDismissingKeyguard(intent); + } + }; + } + + private DozeMachine.State implState(DozeProvider.DozeState s) { + switch (s) { + case UNINITIALIZED: + return DozeMachine.State.UNINITIALIZED; + case INITIALIZED: + return DozeMachine.State.INITIALIZED; + case DOZE: + return DozeMachine.State.DOZE; + case DOZE_AOD: + return DozeMachine.State.DOZE_AOD; + case DOZE_REQUEST_PULSE: + return DozeMachine.State.DOZE_REQUEST_PULSE; + case DOZE_PULSING: + return DozeMachine.State.DOZE_PULSING; + case DOZE_PULSE_DONE: + return DozeMachine.State.DOZE_PULSE_DONE; + case FINISH: + return DozeMachine.State.FINISH; + default: + throw new IllegalArgumentException("Unknown state: " + s); + } + } + + private DozeProvider.DozeState pluginState(DozeMachine.State s) { + switch (s) { + case UNINITIALIZED: + return DozeProvider.DozeState.UNINITIALIZED; + case INITIALIZED: + return DozeProvider.DozeState.INITIALIZED; + case DOZE: + return DozeProvider.DozeState.DOZE; + case DOZE_AOD: + return DozeProvider.DozeState.DOZE_AOD; + case DOZE_REQUEST_PULSE: + return DozeProvider.DozeState.DOZE_REQUEST_PULSE; + case DOZE_PULSING: + return DozeProvider.DozeState.DOZE_PULSING; + case DOZE_PULSE_DONE: + return DozeProvider.DozeState.DOZE_PULSE_DONE; + case FINISH: + return DozeProvider.DozeState.FINISH; + default: + throw new IllegalArgumentException("Unknown state: " + s); + } + } + private static DozeHost getHost(DozeService service) { Application appCandidate = service.getApplication(); final SystemUIApplication app = (SystemUIApplication) appCandidate; @@ -58,7 +180,7 @@ public class DozeFactory { } /** A wrapper around {@link PowerManager.WakeLock} for testability. */ - public static class WakeLock { + public static class WakeLock implements DozeProvider.WakeLock { private final PowerManager.WakeLock mInner; public WakeLock(PowerManager.WakeLock inner) { @@ -80,4 +202,13 @@ public class DozeFactory { return mInner.wrap(runnable); } } + + /** Hack: We need to initialize the plugin listener before doze actually starts. + * This will be unnecessary once we have proper one-shot support */ + public static class Initializer extends SystemUI { + @Override + public void start() { + getInstance(mContext); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index fb940b511b24..e081b53ffda3 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -17,6 +17,7 @@ package com.android.systemui.doze; import android.annotation.NonNull; +import android.app.PendingIntent; /** * Interface the doze service uses to communicate with the rest of system UI. @@ -32,14 +33,16 @@ public interface DozeHost { boolean isNotificationLightOn(); boolean isPulsingBlocked(); - public interface Callback { - void onNewNotifications(); - void onBuzzBeepBlinked(); - void onNotificationLight(boolean on); - void onPowerSaveChanged(boolean active); + void startPendingIntentDismissingKeyguard(PendingIntent intent); + + interface Callback { + default void onNewNotifications() {} + default void onBuzzBeepBlinked() {} + default void onNotificationLight(boolean on) {} + default void onPowerSaveChanged(boolean active) {} } - public interface PulseCallback { + interface PulseCallback { void onPulseStarted(); void onPulseFinished(); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index b3038b96fe04..870d4d1c6a9d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -78,10 +78,10 @@ public class DozeLog { log("pulseFinish"); } - public static void traceNotificationPulse(Context context, long instance) { + public static void traceNotificationPulse(Context context) { if (!ENABLED) return; init(context); - log("notificationPulse instance=" + instance); + log("notificationPulse"); sNotificationPulseStats.append(); } 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/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index bb4ea2d7ee02..9cc927d1fb3a 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -34,7 +34,7 @@ import android.util.Log; import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.statusbar.phone.DozeParameters; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 94cbdd41e220..78b96b34efad 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -38,7 +38,7 @@ public class DozeService extends DreamService implements DozeMachine.Service { setWindowless(true); - mDozeMachine = DozeFactory.assembleMachine(this); + mDozeMachine = DozeFactory.getInstance(getApplication()).assembleMachine(this); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 9df8113b7ba6..84b22ea93b81 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -58,6 +58,7 @@ public class DozeTriggers implements DozeMachine.Part { private final SensorManager mSensorManager; private final Handler mHandler; private final DozeFactory.WakeLock mWakeLock; + private final boolean mAllowPulseTriggers; private final UiModeManager mUiModeManager; private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver(); @@ -68,7 +69,7 @@ public class DozeTriggers implements DozeMachine.Part { public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost, AmbientDisplayConfiguration config, DozeParameters dozeParameters, SensorManager sensorManager, Handler handler, - DozeFactory.WakeLock wakeLock) { + DozeFactory.WakeLock wakeLock, boolean allowPulseTriggers) { mContext = context; mMachine = machine; mDozeHost = dozeHost; @@ -77,6 +78,7 @@ public class DozeTriggers implements DozeMachine.Part { mSensorManager = sensorManager; mHandler = handler; mWakeLock = wakeLock; + mAllowPulseTriggers = allowPulseTriggers; mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, wakeLock, this::onSensor); mUiModeManager = mContext.getSystemService(UiModeManager.class); @@ -87,6 +89,7 @@ public class DozeTriggers implements DozeMachine.Part { mNotificationPulseTime = SystemClock.elapsedRealtime(); if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return; requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */); + DozeLog.traceNotificationPulse(mContext); } private void onWhisper() { @@ -148,7 +151,7 @@ public class DozeTriggers implements DozeMachine.Part { private void requestPulse(final int reason, boolean performedProxCheck) { Assert.isMainThread(); - if (mPulsePending || !canPulse()) { + if (mPulsePending || !mAllowPulseTriggers || !canPulse()) { return; } @@ -306,20 +309,11 @@ public class DozeTriggers implements DozeMachine.Part { private DozeHost.Callback mHostCallback = new DozeHost.Callback() { @Override - public void onNewNotifications() { - } - - @Override public void onBuzzBeepBlinked() { onNotification(); } @Override - public void onNotificationLight(boolean on) { - - } - - @Override public void onPowerSaveChanged(boolean active) { if (active) { onPowerSave(); diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java new file mode 100644 index 000000000000..6d0e77c06132 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.fragments; + +import android.annotation.Nullable; +import android.app.Fragment; +import android.app.FragmentController; +import android.app.FragmentHostCallback; +import android.app.FragmentManager; +import android.app.FragmentManager.FragmentLifecycleCallbacks; +import android.app.FragmentManagerNonConfig; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Parcelable; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.settingslib.applications.InterestingConfigChanges; +import com.android.systemui.SystemUIApplication; +import com.android.systemui.plugins.PluginManager; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + +public class FragmentHostManager { + + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final Context mContext; + private final HashMap<String, ArrayList<FragmentListener>> mListeners = new HashMap<>(); + private final View mRootView; + private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(); + private final FragmentService mManager; + + private FragmentController mFragments; + private FragmentLifecycleCallbacks mLifecycleCallbacks; + + FragmentHostManager(Context context, FragmentService manager, View rootView) { + mContext = PluginManager.getInstance(context).getAllPluginContext(context); + mManager = manager; + mRootView = rootView; + mConfigChanges.applyNewConfig(context.getResources()); + createFragmentHost(null); + } + + private void createFragmentHost(Parcelable savedState) { + mFragments = FragmentController.createController(new HostCallbacks()); + mFragments.attachHost(null); + mLifecycleCallbacks = new FragmentLifecycleCallbacks() { + @Override + public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, + Bundle savedInstanceState) { + FragmentHostManager.this.onFragmentViewCreated(f); + } + + @Override + public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) { + FragmentHostManager.this.onFragmentViewDestroyed(f); + } + }; + mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks, + true); + if (savedState != null) { + mFragments.restoreAllState(savedState, (FragmentManagerNonConfig) null); + } + // For now just keep all fragments in the resumed state. + mFragments.dispatchCreate(); + mFragments.dispatchStart(); + mFragments.dispatchResume(); + } + + private Parcelable destroyFragmentHost() { + mFragments.dispatchPause(); + Parcelable p = mFragments.saveAllState(); + mFragments.dispatchStop(); + mFragments.dispatchDestroy(); + mFragments.getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks); + return p; + } + + public void addTagListener(String tag, FragmentListener listener) { + ArrayList<FragmentListener> listeners = mListeners.get(tag); + if (listeners == null) { + listeners = new ArrayList<>(); + mListeners.put(tag, listeners); + } + listeners.add(listener); + Fragment current = getFragmentManager().findFragmentByTag(tag); + if (current != null && current.getView() != null) { + listener.onFragmentViewCreated(tag, current); + } + } + + // Shouldn't generally be needed, included for completeness sake. + public void removeTagListener(String tag, FragmentListener listener) { + ArrayList<FragmentListener> listeners = mListeners.get(tag); + if (listeners != null && listeners.remove(listener) && listeners.size() == 0) { + mListeners.remove(tag); + } + } + + private void onFragmentViewCreated(Fragment fragment) { + String tag = fragment.getTag(); + + ArrayList<FragmentListener> listeners = mListeners.get(tag); + if (listeners != null) { + listeners.forEach((listener) -> listener.onFragmentViewCreated(tag, fragment)); + } + } + + private void onFragmentViewDestroyed(Fragment fragment) { + String tag = fragment.getTag(); + + ArrayList<FragmentListener> listeners = mListeners.get(tag); + if (listeners != null) { + listeners.forEach((listener) -> listener.onFragmentViewDestroyed(tag, fragment)); + } + } + + /** + * Called when the configuration changed, return true if the fragments + * should be recreated. + */ + protected void onConfigurationChanged(Configuration newConfig) { + if (mConfigChanges.applyNewConfig(mContext.getResources())) { + // Save the old state. + Parcelable p = destroyFragmentHost(); + // Generate a new fragment host and restore its state. + createFragmentHost(p); + } else { + mFragments.dispatchConfigurationChanged(newConfig); + } + } + + private void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + // TODO: Do something? + } + + private View findViewById(int id) { + return mRootView.findViewById(id); + } + + /** + * Note: Values from this shouldn't be cached as they can change after config changes. + */ + public FragmentManager getFragmentManager() { + return mFragments.getFragmentManager(); + } + + public interface FragmentListener { + void onFragmentViewCreated(String tag, Fragment fragment); + + // The facts of lifecycle + // When a fragment is destroyed, you should not talk to it any longer. + default void onFragmentViewDestroyed(String tag, Fragment fragment) { + } + } + + public static FragmentHostManager get(View view) { + try { + return ((SystemUIApplication) view.getContext().getApplicationContext()) + .getComponent(FragmentService.class).getFragmentHostManager(view); + } catch (ClassCastException e) { + // TODO: Some auto handling here? + throw e; + } + } + + class HostCallbacks extends FragmentHostCallback<FragmentHostManager> { + public HostCallbacks() { + super(mContext, FragmentHostManager.this.mHandler, 0); + } + + @Override + public FragmentHostManager onGetHost() { + return FragmentHostManager.this; + } + + @Override + public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + FragmentHostManager.this.dump(prefix, fd, writer, args); + } + + @Override + public boolean onShouldSaveFragmentState(Fragment fragment) { + return true; // True for now. + } + + @Override + public LayoutInflater onGetLayoutInflater() { + return LayoutInflater.from(mContext); + } + + @Override + public boolean onUseFragmentManagerInflaterFactory() { + return true; + } + + @Override + public boolean onHasWindowAnimations() { + return false; + } + + @Override + public int onGetWindowAnimations() { + return 0; + } + + @Override + public void onAttachFragment(Fragment fragment) { + } + + @Override + @Nullable + public View onFindViewById(int id) { + return FragmentHostManager.this.findViewById(id); + } + + @Override + public boolean onHasView() { + return true; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java new file mode 100644 index 000000000000..85cde10b5a53 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.fragments; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.util.ArrayMap; +import android.util.Log; +import android.view.View; + +import com.android.systemui.SystemUI; +import com.android.systemui.SystemUIApplication; + +/** + * Holds a map of root views to FragmentHostStates and generates them as needed. + * Also dispatches the configuration changes to all current FragmentHostStates. + */ +public class FragmentService extends SystemUI { + + private static final String TAG = "FragmentService"; + + private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>(); + private final Handler mHandler = new Handler(); + + @Override + public void start() { + putComponent(FragmentService.class, this); + } + + public FragmentHostManager getFragmentHostManager(View view) { + View root = view.getRootView(); + FragmentHostState state = mHosts.get(root); + if (state == null) { + state = new FragmentHostState(root); + mHosts.put(root, state); + } + return state.getFragmentHostManager(); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + for (FragmentHostState state : mHosts.values()) { + state.sendConfigurationChange(newConfig); + } + } + + private class FragmentHostState { + private final View mView; + + private FragmentHostManager mFragmentHostManager; + + public FragmentHostState(View view) { + mView = view; + mFragmentHostManager = new FragmentHostManager(mContext, FragmentService.this, mView); + } + + public void sendConfigurationChange(Configuration newConfig) { + mHandler.post(() -> handleSendConfigurationChange(newConfig)); + } + + public FragmentHostManager getFragmentHostManager() { + return mFragmentHostManager; + } + + private void handleSendConfigurationChange(Configuration newConfig) { + mFragmentHostManager.onConfigurationChanged(newConfig); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java new file mode 100644 index 000000000000..e107fcd5ebae --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.fragments; + +import android.app.Fragment; +import android.util.Log; +import android.view.View; + +import com.android.systemui.plugins.FragmentBase; +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; + +public class PluginFragmentListener implements PluginListener<Plugin> { + + private static final String TAG = "PluginFragmentListener"; + + private final FragmentHostManager mFragmentHostManager; + private final PluginManager mPluginManager; + private final Class<? extends Fragment> mDefaultClass; + private final int mId; + private final String mTag; + private final Class<? extends FragmentBase> mExpectedInterface; + + public PluginFragmentListener(View view, String tag, int id, + Class<? extends Fragment> defaultFragment, + Class<? extends FragmentBase> expectedInterface) { + mFragmentHostManager = FragmentHostManager.get(view); + mPluginManager = PluginManager.getInstance(view.getContext()); + mExpectedInterface = expectedInterface; + mTag = tag; + mDefaultClass = defaultFragment; + mId = id; + } + + public void startListening(String action, int version) { + try { + setFragment(mDefaultClass.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e); + } + mPluginManager.addPluginListener(action, this, version, false /* Only allow one */); + } + + public void stopListening() { + mPluginManager.removePluginListener(this); + } + + private void setFragment(Fragment fragment) { + mFragmentHostManager.getFragmentManager().beginTransaction() + .replace(mId, fragment, mTag) + .commit(); + } + + @Override + public void onPluginConnected(Plugin plugin) { + try { + mExpectedInterface.cast(plugin); + setFragment((Fragment) plugin); + } catch (ClassCastException e) { + Log.e(TAG, plugin.getClass().getName() + " must be a Fragment and implement " + + mExpectedInterface.getName(), e); + } + } + + @Override + public void onPluginDisconnected(Plugin plugin) { + try { + setFragment(mDefaultClass.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 816d70d3baef..fe9f55f9a1ee 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -136,7 +136,7 @@ public class KeyguardService extends Service { @Override // Binder interface public void onScreenTurnedOn() { - Trace.beginSection("KeyguardService.mBinder#onScreenTurningOn"); + Trace.beginSection("KeyguardService.mBinder#onScreenTurnedOn"); checkPermission(); mKeyguardViewMediator.onScreenTurnedOn(); Trace.endSection(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 9ae341a90cb1..34dc63f12427 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -23,7 +23,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.SearchManager; @@ -285,6 +284,7 @@ public class KeyguardViewMediator extends SystemUI { private LockPatternUtils mLockPatternUtils; private boolean mKeyguardDonePending = false; private boolean mHideAnimationRun = false; + private boolean mHideAnimationRunning = false; private SoundPool mLockSounds; private int mLockSoundId; @@ -515,9 +515,7 @@ public class KeyguardViewMediator extends SystemUI { return; } - if (!mKeyguardDonePending) { - KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */); - } + tryKeyguardDone(true); if (strongAuth) { mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt(); } @@ -545,7 +543,8 @@ public class KeyguardViewMediator extends SystemUI { mKeyguardDonePending = true; mHideAnimationRun = true; - mStatusBarKeyguardViewManager.startPreHideAnimation(null /* finishRunnable */); + mHideAnimationRunning = true; + mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable); mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT, KEYGUARD_DONE_PENDING_TIMEOUT_MS); if (strongAuth) { @@ -565,9 +564,11 @@ public class KeyguardViewMediator extends SystemUI { public void readyForKeyguardDone() { Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone"); if (mKeyguardDonePending) { + mKeyguardDonePending = false; + // Somebody has called keyguardDonePending before, which means that we are // authenticated - KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */); + tryKeyguardDone(true); } Trace.endSection(); } @@ -643,9 +644,7 @@ public class KeyguardViewMediator extends SystemUI { // Assume keyguard is showing (unless it's disabled) until we know for sure... setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled( - KeyguardUpdateMonitor.getCurrentUser())); - updateInputRestrictedLocked(); - mTrustManager.reportKeyguardShowingChanged(); + KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */); mStatusBarKeyguardViewManager = SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext, @@ -1257,7 +1256,7 @@ public class KeyguardViewMediator extends SystemUI { */ public void handleDismiss(boolean allowWhileOccluded) { if (mShowing && (allowWhileOccluded || !mOccluded)) { - mStatusBarKeyguardViewManager.dismiss(); + mStatusBarKeyguardViewManager.dismissAndCollapse(); } } @@ -1493,6 +1492,16 @@ public class KeyguardViewMediator extends SystemUI { } }; + private void tryKeyguardDone(boolean authenticated) { + if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) { + handleKeyguardDone(authenticated); + } else if (!mHideAnimationRun) { + mHideAnimationRun = true; + mHideAnimationRunning = true; + mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable); + } + } + /** * @see #keyguardDone * @see #KEYGUARD_DONE @@ -1609,7 +1618,7 @@ public class KeyguardViewMediator extends SystemUI { private void updateActivityLockScreenState() { Trace.beginSection("KeyguardViewMediator#updateActivityLockScreenState"); try { - ActivityManagerNative.getDefault().setLockScreenShown(mShowing); + ActivityManager.getService().setLockScreenShown(mShowing); } catch (RemoteException e) { } Trace.endSection(); @@ -1671,7 +1680,7 @@ public class KeyguardViewMediator extends SystemUI { // Don't actually hide the Keyguard at the moment, wait for window // manager until it tells us it's safe to do so with // startKeyguardExitAnimation. - ActivityManagerNative.getDefault().keyguardGoingAway(flags); + ActivityManager.getService().keyguardGoingAway(flags); } catch (RemoteException e) { Log.e(TAG, "Error while calling WindowManager", e); } @@ -1679,6 +1688,11 @@ public class KeyguardViewMediator extends SystemUI { } }; + private final Runnable mHideAnimationFinishedRunnable = () -> { + mHideAnimationRunning = false; + tryKeyguardDone(true); + }; + /** * Handle message sent by {@link #hideLocked()} * @see #HIDE @@ -1697,16 +1711,10 @@ public class KeyguardViewMediator extends SystemUI { return; } mHiding = true; + if (mShowing && !mOccluded) { - if (!mHideAnimationRun) { - mStatusBarKeyguardViewManager.startPreHideAnimation(mKeyguardGoingAwayRunnable); - } else { - mKeyguardGoingAwayRunnable.run(); - } + mKeyguardGoingAwayRunnable.run(); } else { - - // Don't try to rely on WindowManager - if Keyguard wasn't showing, window - // manager won't start the exit animation. handleStartKeyguardExitAnimation( SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(), mHideAnimation.getDuration()); @@ -1806,7 +1814,7 @@ public class KeyguardViewMediator extends SystemUI { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); setShowingLocked(true); - mStatusBarKeyguardViewManager.verifyUnlock(); + mStatusBarKeyguardViewManager.dismissAndCollapse(); } Trace.endSection(); } @@ -1969,7 +1977,11 @@ public class KeyguardViewMediator extends SystemUI { } private void setShowingLocked(boolean showing) { - if (showing != mShowing) { + setShowingLocked(showing, false /* forceCallbacks */); + } + + private void setShowingLocked(boolean showing, boolean forceCallbacks) { + if (showing != mShowing || forceCallbacks) { mShowing = showing; int size = mKeyguardStateCallbacks.size(); for (int i = size - 1; i >= 0; i--) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 7b8d27eef8b4..43cfa3249a90 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -16,7 +16,7 @@ package com.android.systemui.pip.phone; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Context; import android.view.IWindowManager; @@ -44,7 +44,7 @@ public class PipManager { */ public void initialize(Context context) { mContext = context; - mActivityManager = ActivityManagerNative.getDefault(); + mActivityManager = ActivityManager.getService(); mWindowManager = WindowManagerGlobal.getWindowManagerService(); mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java new file mode 100644 index 000000000000..e8e8a4d3215a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip.phone; + +/** + * A generic interface for a touch gesture. + */ +public abstract class PipTouchGesture { + + /** + * Handle the touch down. + */ + void onDown(PipTouchState touchState) {} + + /** + * Handle the touch move, and return whether the event was consumed. + */ + boolean onMove(PipTouchState touchState) { + return false; + } + + /** + * Handle the touch up, and return whether the gesture was consumed. + */ + boolean onUp(PipTouchState touchState) { + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index a3593806fb1f..c6dde4623ef3 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -22,6 +22,7 @@ import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN; import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN; +import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -30,9 +31,9 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.ActivityManager.StackInfo; import android.app.IActivityManager; import android.content.Context; +import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; -import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; @@ -43,7 +44,6 @@ import android.view.InputChannel; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.MotionEvent; -import android.view.VelocityTracker; import android.view.ViewConfiguration; import com.android.internal.os.BackgroundThread; @@ -64,10 +64,17 @@ public class PipTouchHandler implements TunerService.Tunable { private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss"; private static final String TUNER_KEY_TAP_THROUGH = "pip_tap_through"; private static final String TUNER_KEY_SNAP_MODE_EDGE = "pip_snap_mode_edge"; + private static final String TUNER_KEY_ALLOW_MINIMIZE = "pip_allow_minimize"; private static final int SNAP_STACK_DURATION = 225; private static final int DISMISS_STACK_DURATION = 375; private static final int EXPAND_STACK_DURATION = 225; + private static final int MINIMIZE_STACK_MAX_DURATION = 200; + + // The fraction of the stack width that the user has to drag offscreen to minimize the PIP + private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.15f; + // The fraction of the stack width that the user has to move when flinging to dismiss the PIP + private static final float DISMISS_FLING_DISTANCE_FRACTION = 0.3f; private final Context mContext; private final IActivityManager mActivityManager; @@ -83,10 +90,16 @@ public class PipTouchHandler implements TunerService.Tunable { private final PipSnapAlgorithm mSnapAlgorithm; private PipMotionHelper mMotionHelper; + // Allow swiping offscreen to dismiss the PIP private boolean mEnableSwipeToDismiss = true; + // Allow dragging the PIP to a location to close it private boolean mEnableDragToDismiss = true; + // Allow tapping on the PIP to show additional controls private boolean mEnableTapThrough = false; + // Allow snapping the PIP to the closest edge and not the corners of the screen private boolean mEnableSnapToEdge = false; + // Allow the PIP to be "docked" slightly offscreen + private boolean mEnableMinimizing = false; private final Rect mPinnedStackBounds = new Rect(); private final Rect mBoundedPinnedStackBounds = new Rect(); @@ -99,16 +112,16 @@ public class PipTouchHandler implements TunerService.Tunable { } }; - private final PointF mDownTouch = new PointF(); - private final PointF mLastTouch = new PointF(); - private boolean mIsDragging; - private boolean mIsSwipingToDismiss; + // Behaviour states private boolean mIsTappingThrough; - private int mActivePointerId; + private boolean mIsMinimized; + // Touch state + private final PipTouchState mTouchState; private final FlingAnimationUtils mFlingAnimationUtils; - private VelocityTracker mVelocityTracker; + private final PipTouchGesture[] mGestures; + // Temporary vars private final Rect mTmpBounds = new Rect(); /** @@ -183,13 +196,19 @@ public class PipTouchHandler implements TunerService.Tunable { mMenuController.addListener(mMenuListener); mDismissViewController = new PipDismissViewController(context); mSnapAlgorithm = new PipSnapAlgorithm(mContext); + mTouchState = new PipTouchState(mViewConfig); mFlingAnimationUtils = new FlingAnimationUtils(context, 2f); + mGestures = new PipTouchGesture[]{ + mDragToDismissGesture, mSwipeToDismissGesture, mTapThroughGesture, mMinimizeGesture, + mDefaultMovementGesture + }; mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler()); registerInputConsumer(); // Register any tuner settings changes TunerService.get(context).addTunable(this, TUNER_KEY_SWIPE_TO_DISMISS, - TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE); + TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE, + TUNER_KEY_ALLOW_MINIMIZE); } @Override @@ -198,6 +217,8 @@ public class PipTouchHandler implements TunerService.Tunable { // Reset back to default mEnableSwipeToDismiss = true; mEnableDragToDismiss = true; + mEnableMinimizing = false; + setMinimizedState(false); mEnableTapThrough = false; mIsTappingThrough = false; mEnableSnapToEdge = false; @@ -211,6 +232,9 @@ public class PipTouchHandler implements TunerService.Tunable { case TUNER_KEY_DRAG_TO_DISMISS: mEnableDragToDismiss = Integer.parseInt(newValue) != 0; break; + case TUNER_KEY_ALLOW_MINIMIZE: + mEnableMinimizing = Integer.parseInt(newValue) != 0; + break; case TUNER_KEY_TAP_THROUGH: mEnableTapThrough = Integer.parseInt(newValue) != 0; mIsTappingThrough = false; @@ -233,6 +257,9 @@ public class PipTouchHandler implements TunerService.Tunable { return true; } + // Update the touch state + mTouchState.onTouchEvent(ev); + switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { // Cancel any existing animations on the pinned stack @@ -241,173 +268,58 @@ public class PipTouchHandler implements TunerService.Tunable { } updateBoundedPinnedStackBounds(true /* updatePinnedStackBounds */); - initOrResetVelocityTracker(); - mVelocityTracker.addMovement(ev); - mActivePointerId = ev.getPointerId(0); - mLastTouch.set(ev.getX(), ev.getY()); - mDownTouch.set(mLastTouch); - mIsDragging = false; + for (PipTouchGesture gesture : mGestures) { + gesture.onDown(mTouchState); + } try { mPinnedStackController.setInInteractiveMode(true); } catch (RemoteException e) { Log.e(TAG, "Could not set dragging state", e); } - if (mEnableDragToDismiss) { - // TODO: Consider setting a timer such at after X time, we show the dismiss - // target if the user hasn't already dragged some distance - mDismissViewController.createDismissTarget(); - } break; } case MotionEvent.ACTION_MOVE: { - // Update the velocity tracker - mVelocityTracker.addMovement(ev); - - int activePointerIndex = ev.findPointerIndex(mActivePointerId); - float x = ev.getX(activePointerIndex); - float y = ev.getY(activePointerIndex); - float left = mPinnedStackBounds.left + (x - mLastTouch.x); - float top = mPinnedStackBounds.top + (y - mLastTouch.y); - - if (!mIsDragging) { - // Check if the pointer has moved far enough - float movement = PointF.length(mDownTouch.x - x, mDownTouch.y - y); - if (movement > mViewConfig.getScaledTouchSlop()) { - mIsDragging = true; - mIsTappingThrough = false; - mMenuController.hideMenu(); - if (mEnableSwipeToDismiss) { - // TODO: this check can have some buffer so that we only start swiping - // after a significant move out of bounds - mIsSwipingToDismiss = !(mBoundedPinnedStackBounds.left <= left && - left <= mBoundedPinnedStackBounds.right) && - Math.abs(mDownTouch.x - x) > Math.abs(y - mLastTouch.y); - } - if (mEnableDragToDismiss) { - mDismissViewController.showDismissTarget(); - } + for (PipTouchGesture gesture : mGestures) { + if (gesture.onMove(mTouchState)) { + break; } } - - if (mIsSwipingToDismiss) { - // Ignore the vertical movement - mTmpBounds.set(mPinnedStackBounds); - mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top); - if (!mTmpBounds.equals(mPinnedStackBounds)) { - mPinnedStackBounds.set(mTmpBounds); - mMotionHelper.resizeToBounds(mPinnedStackBounds); - } - } else if (mIsDragging) { - // Move the pinned stack - if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) { - left = Math.max(mBoundedPinnedStackBounds.left, Math.min( - mBoundedPinnedStackBounds.right, left)); - top = Math.max(mBoundedPinnedStackBounds.top, Math.min( - mBoundedPinnedStackBounds.bottom, top)); - } - mTmpBounds.set(mPinnedStackBounds); - mTmpBounds.offsetTo((int) left, (int) top); - if (!mTmpBounds.equals(mPinnedStackBounds)) { - mPinnedStackBounds.set(mTmpBounds); - mMotionHelper.resizeToBounds(mPinnedStackBounds); - } - } - mLastTouch.set(ev.getX(), ev.getY()); - break; - } - case MotionEvent.ACTION_POINTER_UP: { - // Update the velocity tracker - mVelocityTracker.addMovement(ev); - - int pointerIndex = ev.getActionIndex(); - int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // Select a new active pointer id and reset the movement state - final int newPointerIndex = (pointerIndex == 0) ? 1 : 0; - mActivePointerId = ev.getPointerId(newPointerIndex); - mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex)); - } break; } case MotionEvent.ACTION_UP: { - // Update the velocity tracker - mVelocityTracker.addMovement(ev); - mVelocityTracker.computeCurrentVelocity(1000, - ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity()); - float velocityX = mVelocityTracker.getXVelocity(); - float velocityY = mVelocityTracker.getYVelocity(); - float velocity = PointF.length(velocityX, velocityY); - // Update the movement bounds again if the state has changed since the user started // dragging (ie. when the IME shows) updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */); - if (mIsSwipingToDismiss) { - if (Math.abs(velocityX) > mFlingAnimationUtils.getMinVelocityPxPerSecond()) { - flingToDismiss(velocityX); - } else { - animateToClosestSnapTarget(); - } - } else if (mIsDragging) { - if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) { - flingToSnapTarget(velocity, velocityX, velocityY); - } else { - int activePointerIndex = ev.findPointerIndex(mActivePointerId); - int x = (int) ev.getX(activePointerIndex); - int y = (int) ev.getY(activePointerIndex); - Rect dismissBounds = mEnableDragToDismiss - ? mDismissViewController.getDismissBounds() - : null; - if (dismissBounds != null && dismissBounds.contains(x, y)) { - animateDismissPinnedStack(dismissBounds); - } else { - animateToClosestSnapTarget(); - } + for (PipTouchGesture gesture : mGestures) { + if (gesture.onUp(mTouchState)) { + break; } - } else { - if (mEnableTapThrough) { - if (!mIsTappingThrough) { - mMenuController.showMenu(); - mIsTappingThrough = true; - } - } else { - expandPinnedStackToFullscreen(); - } - } - if (mEnableDragToDismiss) { - mDismissViewController.destroyDismissTarget(); } // Fall through to clean up } case MotionEvent.ACTION_CANCEL: { - mIsDragging = false; - mIsSwipingToDismiss = false; try { mPinnedStackController.setInInteractiveMode(false); } catch (RemoteException e) { Log.e(TAG, "Could not set dragging state", e); } - recycleVelocityTracker(); break; } } return !mIsTappingThrough; } - private void initOrResetVelocityTracker() { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } else { - mVelocityTracker.clear(); - } - } - - private void recycleVelocityTracker() { - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } + /** + * @return whether the current touch state is a horizontal drag offscreen. + */ + private boolean isDraggingOffscreen(PipTouchState touchState) { + PointF lastDelta = touchState.getLastTouchDelta(); + PointF downDelta = touchState.getDownTouchDelta(); + float left = mPinnedStackBounds.left + lastDelta.x; + return !(mBoundedPinnedStackBounds.left <= left && left <= mBoundedPinnedStackBounds.right) + && Math.abs(downDelta.x) > Math.abs(downDelta.y); } /** @@ -449,6 +361,71 @@ public class PipTouchHandler implements TunerService.Tunable { } /** + * Sets the minimized state and notifies the controller. + */ + private void setMinimizedState(boolean isMinimized) { + mIsMinimized = isMinimized; + try { + mPinnedStackController.setIsMinimized(isMinimized); + } catch (RemoteException e) { + Log.e(TAG, "Could not set minimized state", e); + } + } + + /** + * @return whether the given {@param pinnedStackBounds} indicates the PIP should be minimized. + */ + private boolean shouldMinimizedPinnedStack() { + Point displaySize = new Point(); + mContext.getDisplay().getRealSize(displaySize); + if (mPinnedStackBounds.left < 0) { + float offscreenFraction = (float) -mPinnedStackBounds.left / mPinnedStackBounds.width(); + return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION; + } else if (mPinnedStackBounds.right > displaySize.x) { + float offscreenFraction = (float) (mPinnedStackBounds.right - displaySize.x) / + mPinnedStackBounds.width(); + return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION; + } else { + return false; + } + } + + /** + * Flings the minimized PIP to the closest minimized snap target. + */ + private void flingToMinimizedSnapTarget(float velocityY) { + // We currently only allow flinging the minimized stack up and down, so just lock the + // movement bounds to the current stack bounds horizontally + Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top, + mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom); + Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds, + 0 /* velocityX */, velocityY); + if (!mPinnedStackBounds.equals(toBounds)) { + mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds, + toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener); + mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0, + distanceBetweenRectOffsets(mPinnedStackBounds, toBounds), + velocityY); + mPinnedStackBoundsAnimator.start(); + } + } + + /** + * Animates the PIP to the minimized state, slightly offscreen. + */ + private void animateToClosestMinimizedTarget() { + Point displaySize = new Point(); + mContext.getDisplay().getRealSize(displaySize); + Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds, + mPinnedStackBounds); + mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize); + mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds, + toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, + mUpdatePinnedStackBoundsListener); + mPinnedStackBoundsAnimator.start(); + } + + /** * Flings the PIP to the closest snap target. */ private void flingToSnapTarget(float velocity, float velocityX, float velocityY) { @@ -478,12 +455,26 @@ public class PipTouchHandler implements TunerService.Tunable { } /** + * @return whether the velocity is coincident with the current pinned stack bounds to be + * considered a fling to dismiss. + */ + private boolean isFlingToDismiss(float velocityX) { + Point displaySize = new Point(); + mContext.getDisplay().getRealSize(displaySize); + return (mPinnedStackBounds.right > displaySize.x && velocityX > 0) || + (mPinnedStackBounds.left < 0 && velocityX < 0); + } + + /** * Flings the PIP to dismiss it offscreen. */ private void flingToDismiss(float velocityX) { + Point displaySize = new Point(); + mContext.getDisplay().getRealSize(displaySize); float offsetX = velocityX > 0 - ? mBoundedPinnedStackBounds.right + 2 * mPinnedStackBounds.width() - : mBoundedPinnedStackBounds.left - 2 * mPinnedStackBounds.width(); + ? displaySize.x + mPinnedStackBounds.width() + : -mPinnedStackBounds.width(); + Rect toBounds = new Rect(mPinnedStackBounds); toBounds.offsetTo((int) offsetX, toBounds.top); if (!mPinnedStackBounds.equals(toBounds)) { @@ -495,13 +486,7 @@ public class PipTouchHandler implements TunerService.Tunable { mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - BackgroundThread.getHandler().post(() -> { - try { - mActivityManager.removeStack(PINNED_STACK_ID); - } catch (RemoteException e) { - Log.e(TAG, "Failed to remove PIP", e); - } - }); + BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack); } }); mPinnedStackBoundsAnimator.start(); @@ -521,13 +506,7 @@ public class PipTouchHandler implements TunerService.Tunable { mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - BackgroundThread.getHandler().post(() -> { - try { - mActivityManager.removeStack(PINNED_STACK_ID); - } catch (RemoteException e) { - Log.e(TAG, "Failed to remove PIP", e); - } - }); + BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack); } }); mPinnedStackBoundsAnimator.start(); @@ -549,6 +528,27 @@ public class PipTouchHandler implements TunerService.Tunable { } /** + * Tries to the move the pinned stack to the given {@param bounds}. + */ + private void movePinnedStack(Rect bounds) { + if (!bounds.equals(mPinnedStackBounds)) { + mPinnedStackBounds.set(bounds); + mMotionHelper.resizeToBounds(mPinnedStackBounds); + } + } + + /** + * Dismisses the pinned stack. + */ + private void dismissPinnedStack() { + try { + mActivityManager.removeStack(PINNED_STACK_ID); + } catch (RemoteException e) { + Log.e(TAG, "Failed to remove PIP", e); + } + } + + /** * Updates the movement bounds of the pinned stack. */ private void updateBoundedPinnedStackBounds(boolean updatePinnedStackBounds) { @@ -572,4 +572,237 @@ public class PipTouchHandler implements TunerService.Tunable { private float distanceBetweenRectOffsets(Rect r1, Rect r2) { return PointF.length(r1.left - r2.left, r1.top - r2.top); } + + /** + * Gesture controlling dragging over a target to dismiss the PIP. + */ + private PipTouchGesture mDragToDismissGesture = new PipTouchGesture() { + @Override + public void onDown(PipTouchState touchState) { + if (mEnableDragToDismiss) { + // TODO: Consider setting a timer such at after X time, we show the dismiss + // target if the user hasn't already dragged some distance + mDismissViewController.createDismissTarget(); + } + } + + @Override + boolean onMove(PipTouchState touchState) { + if (mEnableDragToDismiss && touchState.startedDragging()) { + mDismissViewController.showDismissTarget(); + } + return false; + } + + @Override + public boolean onUp(PipTouchState touchState) { + if (mEnableDragToDismiss) { + try { + if (touchState.isDragging()) { + Rect dismissBounds = mDismissViewController.getDismissBounds(); + PointF lastTouch = touchState.getLastTouchPosition(); + if (dismissBounds.contains((int) lastTouch.x, (int) lastTouch.y)) { + animateDismissPinnedStack(dismissBounds); + return true; + } + } + } finally { + mDismissViewController.destroyDismissTarget(); + } + } + return false; + } + }; + + /**** Gestures ****/ + + /** + * Gesture controlling swiping offscreen to dismiss the PIP. + */ + private PipTouchGesture mSwipeToDismissGesture = new PipTouchGesture() { + @Override + boolean onMove(PipTouchState touchState) { + if (mEnableSwipeToDismiss) { + boolean isDraggingOffscreen = isDraggingOffscreen(touchState); + + if (touchState.startedDragging() && isDraggingOffscreen) { + // Reset the minimized state once we drag horizontally + setMinimizedState(false); + } + + if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) { + // Move the pinned stack, but ignore the vertical movement + float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x; + mTmpBounds.set(mPinnedStackBounds); + mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top); + if (!mTmpBounds.equals(mPinnedStackBounds)) { + mPinnedStackBounds.set(mTmpBounds); + mMotionHelper.resizeToBounds(mPinnedStackBounds); + } + return true; + } + } + return false; + } + + @Override + public boolean onUp(PipTouchState touchState) { + if (mEnableSwipeToDismiss && touchState.isDragging()) { + PointF vel = touchState.getVelocity(); + PointF downDelta = touchState.getDownTouchDelta(); + float minFlingVel = mFlingAnimationUtils.getMinVelocityPxPerSecond(); + float flingVelScale = mEnableMinimizing ? 3f : 2f; + if (Math.abs(vel.x) > (flingVelScale * minFlingVel)) { + // Determine if this gesture is actually a fling to dismiss + if (isFlingToDismiss(vel.x) && Math.abs(downDelta.x) >= + (DISMISS_FLING_DISTANCE_FRACTION * mPinnedStackBounds.width())) { + flingToDismiss(vel.x); + } else { + flingToSnapTarget(vel.length(), vel.x, vel.y); + } + return true; + } + } + return false; + } + }; + + /** + * Gesture controlling dragging the PIP slightly offscreen to minimize it. + */ + private PipTouchGesture mMinimizeGesture = new PipTouchGesture() { + @Override + boolean onMove(PipTouchState touchState) { + if (mEnableMinimizing) { + boolean isDraggingOffscreen = isDraggingOffscreen(touchState); + if (touchState.startedDragging() && isDraggingOffscreen) { + // Reset the minimized state once we drag horizontally + setMinimizedState(false); + } + + if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) { + // Move the pinned stack, but ignore the vertical movement + float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x; + mTmpBounds.set(mPinnedStackBounds); + mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top); + if (!mTmpBounds.equals(mPinnedStackBounds)) { + mPinnedStackBounds.set(mTmpBounds); + mMotionHelper.resizeToBounds(mPinnedStackBounds); + } + return true; + } else if (mIsMinimized && touchState.isDragging()) { + // Move the pinned stack, but ignore the horizontal movement + PointF lastDelta = touchState.getLastTouchDelta(); + float top = mPinnedStackBounds.top + lastDelta.y; + top = Math.max(mBoundedPinnedStackBounds.top, Math.min( + mBoundedPinnedStackBounds.bottom, top)); + mTmpBounds.set(mPinnedStackBounds); + mTmpBounds.offsetTo(mPinnedStackBounds.left, (int) top); + movePinnedStack(mTmpBounds); + return true; + } + } + return false; + } + + @Override + public boolean onUp(PipTouchState touchState) { + if (mEnableMinimizing) { + if (touchState.isDragging()) { + if (isDraggingOffscreen(touchState)) { + if (shouldMinimizedPinnedStack()) { + setMinimizedState(true); + animateToClosestMinimizedTarget(); + return true; + } + } else if (mIsMinimized) { + PointF vel = touchState.getVelocity(); + if (vel.length() > mFlingAnimationUtils.getMinVelocityPxPerSecond()) { + flingToMinimizedSnapTarget(vel.y); + } else { + animateToClosestMinimizedTarget(); + } + return true; + } + } else if (mIsMinimized) { + setMinimizedState(false); + animateToClosestSnapTarget(); + return true; + } + } + return false; + } + }; + + /** + * Gesture controlling tapping on the PIP to show an overlay. + */ + private PipTouchGesture mTapThroughGesture = new PipTouchGesture() { + @Override + boolean onMove(PipTouchState touchState) { + if (mEnableTapThrough && touchState.startedDragging()) { + mIsTappingThrough = false; + mMenuController.hideMenu(); + } + return false; + } + + @Override + public boolean onUp(PipTouchState touchState) { + if (mEnableTapThrough && !touchState.isDragging() && !mIsTappingThrough) { + mMenuController.showMenu(); + mIsTappingThrough = true; + return true; + } + return false; + } + }; + + /** + * Gesture controlling normal movement of the PIP. + */ + private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() { + @Override + boolean onMove(PipTouchState touchState) { + if (touchState.startedDragging()) { + // For now, once the user has started a drag that the other gestures have not + // intercepted, disallow those gestures from intercepting again to drag offscreen + touchState.setDisallowDraggingOffscreen(); + } + + if (touchState.isDragging()) { + // Move the pinned stack freely + PointF lastDelta = touchState.getLastTouchDelta(); + float left = mPinnedStackBounds.left + lastDelta.x; + float top = mPinnedStackBounds.top + lastDelta.y; + if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) { + left = Math.max(mBoundedPinnedStackBounds.left, Math.min( + mBoundedPinnedStackBounds.right, left)); + top = Math.max(mBoundedPinnedStackBounds.top, Math.min( + mBoundedPinnedStackBounds.bottom, top)); + } + mTmpBounds.set(mPinnedStackBounds); + mTmpBounds.offsetTo((int) left, (int) top); + movePinnedStack(mTmpBounds); + return true; + } + return false; + } + + @Override + public boolean onUp(PipTouchState touchState) { + if (touchState.isDragging()) { + PointF vel = mTouchState.getVelocity(); + float velocity = PointF.length(vel.x, vel.y); + if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) { + flingToSnapTarget(velocity, vel.x, vel.y); + } else { + animateToClosestSnapTarget(); + } + } else { + expandPinnedStackToFullscreen(); + } + return true; + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java new file mode 100644 index 000000000000..17d9864e4d25 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip.phone; + +import android.app.IActivityManager; +import android.graphics.PointF; +import android.view.IPinnedStackController; +import android.view.IPinnedStackListener; +import android.view.IWindowManager; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +/** + * This keeps track of the touch state throughout the current touch gesture. + */ +public class PipTouchState { + + private ViewConfiguration mViewConfig; + + private VelocityTracker mVelocityTracker; + private final PointF mDownTouch = new PointF(); + private final PointF mDownDelta = new PointF(); + private final PointF mLastTouch = new PointF(); + private final PointF mLastDelta = new PointF(); + private final PointF mVelocity = new PointF(); + private boolean mIsDragging = false; + private boolean mStartedDragging = false; + private boolean mAllowDraggingOffscreen = false; + private int mActivePointerId; + + public PipTouchState(ViewConfiguration viewConfig) { + mViewConfig = viewConfig; + } + + /** + * Processess a given touch event and updates the state. + */ + public void onTouchEvent(MotionEvent ev) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: { + // Initialize the velocity tracker + initOrResetVelocityTracker(); + mActivePointerId = ev.getPointerId(0); + mLastTouch.set(ev.getX(), ev.getY()); + mDownTouch.set(mLastTouch); + mIsDragging = false; + mStartedDragging = false; + mAllowDraggingOffscreen = true; + break; + } + case MotionEvent.ACTION_MOVE: { + // Update the velocity tracker + mVelocityTracker.addMovement(ev); + int pointerIndex = ev.findPointerIndex(mActivePointerId); + float x = ev.getX(pointerIndex); + float y = ev.getY(pointerIndex); + mLastDelta.set(x - mLastTouch.x, y - mLastTouch.y); + mDownDelta.set(x - mDownTouch.x, y - mDownTouch.y); + + boolean hasMovedBeyondTap = mDownDelta.length() > mViewConfig.getScaledTouchSlop(); + if (!mIsDragging) { + if (hasMovedBeyondTap) { + mIsDragging = true; + mStartedDragging = true; + } + } else { + mStartedDragging = false; + } + mLastTouch.set(x, y); + break; + } + case MotionEvent.ACTION_POINTER_UP: { + // Update the velocity tracker + mVelocityTracker.addMovement(ev); + + int pointerIndex = ev.getActionIndex(); + int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // Select a new active pointer id and reset the movement state + final int newPointerIndex = (pointerIndex == 0) ? 1 : 0; + mActivePointerId = ev.getPointerId(newPointerIndex); + mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex)); + } + break; + } + case MotionEvent.ACTION_UP: { + // Update the velocity tracker + mVelocityTracker.addMovement(ev); + mVelocityTracker.computeCurrentVelocity(1000, + mViewConfig.getScaledMaximumFlingVelocity()); + mVelocity.set(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity()); + + int pointerIndex = ev.findPointerIndex(mActivePointerId); + mLastTouch.set(ev.getX(pointerIndex), ev.getY(pointerIndex)); + + // Fall through to clean up + } + case MotionEvent.ACTION_CANCEL: { + recycleVelocityTracker(); + break; + } + } + } + + /** + * @return the velocity of the active touch pointer at the point it is lifted off the screen. + */ + public PointF getVelocity() { + return mVelocity; + } + + /** + * @return the last touch position of the active pointer. + */ + public PointF getLastTouchPosition() { + return mLastTouch; + } + + /** + * @return the movement delta between the last handled touch event and the previous touch + * position. + */ + public PointF getLastTouchDelta() { + return mLastDelta; + } + + /** + * @return the movement delta between the last handled touch event and the down touch + * position. + */ + public PointF getDownTouchDelta() { + return mDownDelta; + } + + /** + * @return whether the user has started dragging. + */ + public boolean isDragging() { + return mIsDragging; + } + + /** + * @return whether the user has started dragging just in the last handled touch event. + */ + public boolean startedDragging() { + return mStartedDragging; + } + + /** + * Disallows dragging offscreen for the duration of the current gesture. + */ + public void setDisallowDraggingOffscreen() { + mAllowDraggingOffscreen = false; + } + + /** + * @return whether dragging offscreen is allowed during this gesture. + */ + public boolean allowDraggingOffscreen() { + return mAllowDraggingOffscreen; + } + + private void initOrResetVelocityTracker() { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + } + + private void recycleVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 5b93aa2ca930..a6226565c4f9 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -16,9 +16,9 @@ package com.android.systemui.pip.tv; +import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -208,7 +208,7 @@ public class PipManager { mInitialized = true; mContext = context; - mActivityManager = ActivityManagerNative.getDefault(); + mActivityManager = ActivityManager.getService(); mWindowManager = WindowManagerGlobal.getWindowManagerService(); SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener); IntentFilter intentFilter = new IntentFilter(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index e1cd14335dc2..dc42adc6e344 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -20,7 +20,7 @@ import android.view.View.OnAttachStateChangeListener; import android.view.View.OnLayoutChangeListener; import android.widget.TextView; -import com.android.systemui.plugins.qs.QSContainer; +import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.PagedTileLayout.PageListener; import com.android.systemui.qs.QSPanel.QSTileLayout; import com.android.systemui.qs.QSTile.Host.Callback; @@ -47,7 +47,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha private final ArrayList<View> mTopFiveQs = new ArrayList<>(); private final QuickQSPanel mQuickQsPanel; private final QSPanel mQsPanel; - private final QSContainer mQsContainer; + private final QS mQs; private PagedTileLayout mPagedLayout; @@ -67,12 +67,15 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha private float mLastPosition; private QSTileHost mHost; - public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) { - mQsContainer = container; + public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel) { + mQs = qs; mQuickQsPanel = quickPanel; mQsPanel = panel; mQsPanel.addOnAttachStateChangeListener(this); - container.addOnLayoutChangeListener(this); + qs.getView().addOnLayoutChangeListener(this); + if (mQsPanel.isAttachedToWindow()) { + onViewAttachedToWindow(null); + } QSTileLayout tileLayout = mQsPanel.getTileLayout(); if (tileLayout instanceof PagedTileLayout) { mPagedLayout = ((PagedTileLayout) tileLayout); @@ -102,7 +105,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha @Override public void onViewAttachedToWindow(View v) { - TunerService.get(mQsContainer.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION, + TunerService.get(mQs.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION, MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES); } @@ -111,7 +114,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha if (mHost != null) { mHost.removeCallback(this); } - TunerService.get(mQsContainer.getContext()).removeTunable(this); + TunerService.get(mQs.getContext()).removeTunable(this); } @Override @@ -124,7 +127,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha } else if (MOVE_FULL_ROWS.equals(key)) { mFullRows = newValue == null || Integer.parseInt(newValue) != 0; } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) { - mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext()); + mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQs.getContext()); clearAnimationState(); } updateAnimators(); @@ -166,13 +169,14 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha } final TextView label = ((QSTileView) tileView).getLabel(); final View tileIcon = tileView.getIcon().getIconView(); + View view = mQs.getView(); if (count < mNumQuickTiles && mAllowFancy) { // Quick tiles. QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile); lastX = loc1[0]; - getRelativePosition(loc1, quickTileView.getIcon().getIconView(), mQsContainer); - getRelativePosition(loc2, tileIcon, mQsContainer); + getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view); + getRelativePosition(loc2, tileIcon, view); final int xDiff = loc2[0] - loc1[0]; final int yDiff = loc2[1] - loc1[1]; lastXDiff = loc1[0] - lastX; @@ -198,7 +202,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha // This makes the extra icons seems as if they are coming from positions in the // quick panel. loc1[0] += lastXDiff; - getRelativePosition(loc2, tileIcon, mQsContainer); + getRelativePosition(loc2, tileIcon, view); final int xDiff = loc2[0] - loc1[0]; final int yDiff = loc2[1] - loc1[1]; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index f345172752ba..f4da5ecc09ce 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -16,53 +16,34 @@ package com.android.systemui.qs; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; +import android.widget.FrameLayout; -import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer; +import com.android.systemui.plugins.qs.QS.HeightListener; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; import com.android.systemui.statusbar.phone.QSTileHost; import com.android.systemui.statusbar.phone.QuickStatusBarHeader; -import com.android.systemui.statusbar.stack.StackStateAnimator; /** * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader} - * - * Also manages animations for the QS Header and Panel. */ -public class QSContainerImpl extends QSContainer { - private static final String TAG = "QSContainer"; - private static final boolean DEBUG = false; +public class QSContainerImpl extends FrameLayout { private final Point mSizePoint = new Point(); - private final Rect mQsBounds = new Rect(); private int mHeightOverride = -1; - protected QSPanel mQSPanel; - private QSDetail mQSDetail; - protected QuickStatusBarHeader mHeader; + protected View mQSPanel; + private View mQSDetail; + protected View mHeader; protected float mQsExpansion; - private boolean mQsExpanded; - private boolean mHeaderAnimating; - private boolean mKeyguardShowing; - private boolean mStackScrollerOverscrolling; - - private long mDelay; - private QSAnimator mQSAnimator; private QSCustomizer mQSCustomizer; - private HeightListener mPanelView; - private boolean mListening; public QSContainerImpl(Context context, AttributeSet attrs) { super(context, attrs); @@ -71,31 +52,10 @@ public class QSContainerImpl extends QSContainer { @Override protected void onFinishInflate() { super.onFinishInflate(); - mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel); - mQSDetail = (QSDetail) findViewById(R.id.qs_detail); - mHeader = (QuickStatusBarHeader) findViewById(R.id.header); - mQSDetail.setQsPanel(mQSPanel, mHeader); - mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel), - mQSPanel); + mQSPanel = findViewById(R.id.quick_settings_panel); + mQSDetail = findViewById(R.id.qs_detail); + mHeader = findViewById(R.id.header); mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize); - mQSCustomizer.setQsContainer(this); - } - - @Override - public void onRtlPropertiesChanged(int layoutDirection) { - super.onRtlPropertiesChanged(layoutDirection); - mQSAnimator.onRtlChanged(); - } - - public void setHost(QSTileHost qsh) { - mQSPanel.setHost(qsh, mQSCustomizer); - mHeader.setQSPanel(mQSPanel); - mQSDetail.setHost(qsh); - mQSAnimator.setHost(qsh); - } - - public void setPanelView(HeightListener panelView) { - mPanelView = panelView; } @Override @@ -111,8 +71,8 @@ public class QSContainerImpl extends QSContainer { super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); - // QSCustomizer is always be the height of the screen, but do this after - // other measuring to avoid changing the height of the QSContainer. + // QSCustomizer will always be the height of the screen, but do this after + // other measuring to avoid changing the height of the QS. getDisplay().getRealSize(mSizePoint); mQSCustomizer.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY)); @@ -124,10 +84,6 @@ public class QSContainerImpl extends QSContainer { updateBottom(); } - public boolean isCustomizing() { - return mQSCustomizer.isCustomizing(); - } - /** * Overrides the height of this view (post-layout), so that the content is clipped to that * height and the background is set to that height. @@ -139,41 +95,7 @@ public class QSContainerImpl extends QSContainer { updateBottom(); } - @Override - public void setContainer(ViewGroup container) { - if (container instanceof NotificationsQuickSettingsContainer) { - mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container); - } - } - - /** - * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that - * during closing the detail panel, this already returns the smaller height. - */ - public int getDesiredHeight() { - if (isCustomizing()) { - return getHeight(); - } - if (mQSDetail.isClosingDetail()) { - int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin - + mQSPanel.getMeasuredHeight(); - return panelHeight + getPaddingBottom(); - } else { - return getMeasuredHeight(); - } - } - - public void notifyCustomizeChanged() { - // The customize state changed, so our height changed. - updateBottom(); - mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE); - mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE); - // Let the panel know the position changed and it needs to update where notifications - // and whatnot are. - mPanelView.onQsHeightChanged(); - } - - private void updateBottom() { + void updateBottom() { int height = calculateContainerHeight(); setBottom(getTop() + height); mQSDetail.setBottom(getTop() + height); @@ -182,162 +104,12 @@ public class QSContainerImpl extends QSContainer { protected int calculateContainerHeight() { int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight(); return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight() - : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight())) - + mHeader.getCollapsedHeight(); - } - - private void updateQsState() { - boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating; - mQSPanel.setExpanded(mQsExpanded); - mQSDetail.setExpanded(mQsExpanded); - mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating) - ? View.VISIBLE - : View.INVISIBLE); - mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating) - || (mQsExpanded && !mStackScrollerOverscrolling)); - mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE); - } - - public BaseStatusBarHeader getHeader() { - return mHeader; - } - - public QSPanel getQsPanel() { - return mQSPanel; - } - - public QSCustomizer getCustomizer() { - return mQSCustomizer; + : (int) (mQsExpansion * (heightOverride - mHeader.getHeight())) + + mHeader.getHeight(); } - public boolean isShowingDetail() { - return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail(); - } - - public void setHeaderClickable(boolean clickable) { - if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable); - mHeader.setClickable(clickable); - } - - public void setExpanded(boolean expanded) { - if (DEBUG) Log.d(TAG, "setExpanded " + expanded); - mQsExpanded = expanded; - mQSPanel.setListening(mListening && mQsExpanded); - updateQsState(); - } - - public void setKeyguardShowing(boolean keyguardShowing) { - if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing); - mKeyguardShowing = keyguardShowing; - mQSAnimator.setOnKeyguard(keyguardShowing); - updateQsState(); - } - - public void setOverscrolling(boolean stackScrollerOverscrolling) { - if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling); - mStackScrollerOverscrolling = stackScrollerOverscrolling; - updateQsState(); - } - - public void setListening(boolean listening) { - if (DEBUG) Log.d(TAG, "setListening " + listening); - mListening = listening; - mHeader.setListening(listening); - mQSPanel.setListening(mListening && mQsExpanded); - } - - public void setHeaderListening(boolean listening) { - mHeader.setListening(listening); - } - - public void setQsExpansion(float expansion, float headerTranslation) { - if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation); + public void setExpansion(float expansion) { mQsExpansion = expansion; - final float translationScaleY = expansion - 1; - if (!mHeaderAnimating) { - setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight()) - : headerTranslation); - } - mHeader.setExpansion(mKeyguardShowing ? 1 : expansion); - mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight()); - mQSDetail.setFullyExpanded(expansion == 1); - mQSAnimator.setPosition(expansion); updateBottom(); - - // Set bounds on the QS panel so it doesn't run over the header. - mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion)); - mQsBounds.right = mQSPanel.getWidth(); - mQsBounds.bottom = mQSPanel.getHeight(); - mQSPanel.setClipBounds(mQsBounds); - } - - public void animateHeaderSlidingIn(long delay) { - if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn"); - // If the QS is already expanded we don't need to slide in the header as it's already - // visible. - if (!mQsExpanded) { - mHeaderAnimating = true; - mDelay = delay; - getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn); - } - } - - public void animateHeaderSlidingOut() { - if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut"); - mHeaderAnimating = true; - animate().y(-mHeader.getHeight()) - .setStartDelay(0) - .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - animate().setListener(null); - mHeaderAnimating = false; - updateQsState(); - } - }) - .start(); - } - - @Override - public void closeDetail() { - mQSPanel.closeDetail(); - } - - private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn - = new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - getViewTreeObserver().removeOnPreDrawListener(this); - animate() - .translationY(0f) - .setStartDelay(mDelay) - .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setListener(mAnimateHeaderSlidingInListener) - .start(); - setY(-mHeader.getHeight()); - return true; - } - }; - - private final Animator.AnimatorListener mAnimateHeaderSlidingInListener - = new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mHeaderAnimating = false; - updateQsState(); - } - }; - - public int getQsMinExpansionHeight() { - return mHeader.getHeight(); - } - - @Override - public void hideImmediately() { - animate().cancel(); - setY(-mHeader.getHeight()); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 2b9320bfa642..5027144721f4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -35,9 +35,9 @@ import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader; -import com.android.systemui.plugins.qs.QSContainer.Callback; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader; +import com.android.systemui.plugins.qs.QS.Callback; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.statusbar.phone.QSTileHost; public class QSDetail extends LinearLayout { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java new file mode 100644 index 000000000000..c8f167063add --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.qs; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.annotation.Nullable; +import android.app.Fragment; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout.LayoutParams; + +import com.android.systemui.Interpolators; +import com.android.systemui.R; +import com.android.systemui.plugins.qs.QS; +import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; +import com.android.systemui.statusbar.phone.QSTileHost; +import com.android.systemui.statusbar.phone.QuickStatusBarHeader; +import com.android.systemui.statusbar.stack.StackStateAnimator; + +public class QSFragment extends Fragment implements QS { + private static final String TAG = "QS"; + private static final boolean DEBUG = false; + + private final Rect mQsBounds = new Rect(); + private boolean mQsExpanded; + private boolean mHeaderAnimating; + private boolean mKeyguardShowing; + private boolean mStackScrollerOverscrolling; + + private long mDelay; + + private QSAnimator mQSAnimator; + private HeightListener mPanelView; + protected QuickStatusBarHeader mHeader; + private QSCustomizer mQSCustomizer; + protected QSPanel mQSPanel; + private QSDetail mQSDetail; + private boolean mListening; + private QSContainerImpl mContainer; + private int mLayoutDirection; + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.qs_panel, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mQSPanel = (QSPanel) view.findViewById(R.id.quick_settings_panel); + mQSDetail = (QSDetail) view.findViewById(R.id.qs_detail); + mHeader = (QuickStatusBarHeader) view.findViewById(R.id.header); + mContainer = (QSContainerImpl) view; + + mQSDetail.setQsPanel(mQSPanel, mHeader); + mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel), + mQSPanel); + mQSCustomizer = (QSCustomizer) view.findViewById(R.id.qs_customize); + mQSCustomizer.setQs(this); + } + + public void setPanelView(HeightListener panelView) { + mPanelView = panelView; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (newConfig.getLayoutDirection() != mLayoutDirection) { + mLayoutDirection = newConfig.getLayoutDirection(); + mQSAnimator.onRtlChanged(); + } + } + + @Override + public void setContainer(ViewGroup container) { + if (container instanceof NotificationsQuickSettingsContainer) { + mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container); + } + } + + public boolean isCustomizing() { + return mQSCustomizer.isCustomizing(); + } + + public void setHost(QSTileHost qsh) { + mQSPanel.setHost(qsh, mQSCustomizer); + mHeader.setQSPanel(mQSPanel); + mQSDetail.setHost(qsh); + mQSAnimator.setHost(qsh); + } + + private void updateQsState() { + final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling + || mHeaderAnimating; + mQSPanel.setExpanded(mQsExpanded); + mQSDetail.setExpanded(mQsExpanded); + mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating) + ? View.VISIBLE + : View.INVISIBLE); + mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating) + || (mQsExpanded && !mStackScrollerOverscrolling)); + mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE); + } + + public BaseStatusBarHeader getHeader() { + return mHeader; + } + + public QSPanel getQsPanel() { + return mQSPanel; + } + + public QSCustomizer getCustomizer() { + return mQSCustomizer; + } + + public boolean isShowingDetail() { + return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail(); + } + + public void setHeaderClickable(boolean clickable) { + if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable); + mHeader.setClickable(clickable); + } + + public void setExpanded(boolean expanded) { + if (DEBUG) Log.d(TAG, "setExpanded " + expanded); + mQsExpanded = expanded; + mQSPanel.setListening(mListening && mQsExpanded); + updateQsState(); + } + + public void setKeyguardShowing(boolean keyguardShowing) { + if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing); + mKeyguardShowing = keyguardShowing; + mQSAnimator.setOnKeyguard(keyguardShowing); + updateQsState(); + } + + public void setOverscrolling(boolean stackScrollerOverscrolling) { + if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling); + mStackScrollerOverscrolling = stackScrollerOverscrolling; + updateQsState(); + } + + public void setListening(boolean listening) { + if (DEBUG) Log.d(TAG, "setListening " + listening); + mListening = listening; + mHeader.setListening(listening); + mQSPanel.setListening(mListening && mQsExpanded); + } + + public void setHeaderListening(boolean listening) { + mHeader.setListening(listening); + } + + public void setQsExpansion(float expansion, float headerTranslation) { + if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation); + mContainer.setExpansion(expansion); + final float translationScaleY = expansion - 1; + if (!mHeaderAnimating) { + getView().setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight()) + : headerTranslation); + } + mHeader.setExpansion(mKeyguardShowing ? 1 : expansion); + mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight()); + mQSDetail.setFullyExpanded(expansion == 1); + mQSAnimator.setPosition(expansion); + + // Set bounds on the QS panel so it doesn't run over the header. + mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion)); + mQsBounds.right = mQSPanel.getWidth(); + mQsBounds.bottom = mQSPanel.getHeight(); + mQSPanel.setClipBounds(mQsBounds); + } + + public void animateHeaderSlidingIn(long delay) { + if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn"); + // If the QS is already expanded we don't need to slide in the header as it's already + // visible. + if (!mQsExpanded) { + mHeaderAnimating = true; + mDelay = delay; + getView().getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn); + } + } + + public void animateHeaderSlidingOut() { + if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut"); + mHeaderAnimating = true; + getView().animate().y(-mHeader.getHeight()) + .setStartDelay(0) + .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + getView().animate().setListener(null); + mHeaderAnimating = false; + updateQsState(); + } + }) + .start(); + } + + @Override + public void closeDetail() { + mQSPanel.closeDetail(); + } + + public void notifyCustomizeChanged() { + // The customize state changed, so our height changed. + mContainer.updateBottom(); + mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE); + mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE); + // Let the panel know the position changed and it needs to update where notifications + // and whatnot are. + mPanelView.onQsHeightChanged(); + } + + /** + * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that + * during closing the detail panel, this already returns the smaller height. + */ + public int getDesiredHeight() { + if (mQSCustomizer.isCustomizing()) { + return getView().getHeight(); + } + if (mQSDetail.isClosingDetail()) { + int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin + + mQSPanel.getMeasuredHeight(); + return panelHeight + getView().getPaddingBottom(); + } else { + return getView().getMeasuredHeight(); + } + } + + @Override + public void setHeightOverride(int desiredHeight) { + mContainer.setHeightOverride(desiredHeight); + } + + public int getQsMinExpansionHeight() { + return mHeader.getHeight(); + } + + @Override + public void hideImmediately() { + getView().animate().cancel(); + getView().setY(-mHeader.getHeight()); + } + + private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn + = new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + getView().getViewTreeObserver().removeOnPreDrawListener(this); + getView().animate() + .translationY(0f) + .setStartDelay(mDelay) + .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setListener(mAnimateHeaderSlidingInListener) + .start(); + getView().setY(-mHeader.getHeight()); + return true; + } + }; + + private final Animator.AnimatorListener mAnimateHeaderSlidingInListener + = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mHeaderAnimating = false; + updateQsState(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index c699e275ac11..e55ff70c35c2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -28,10 +28,10 @@ import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSTile.Host.Callback; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.qs.external.CustomTile; @@ -60,7 +60,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { protected boolean mExpanded; protected boolean mListening; - private QSContainer.Callback mCallback; + private QS.Callback mCallback; private BrightnessController mBrightnessController; protected QSTileHost mHost; @@ -171,7 +171,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { return mBrightnessView; } - public void setCallback(QSContainer.Callback callback) { + public void setCallback(QS.Callback callback) { mCallback = callback; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 39ce324365a7..4341d17a7753 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -29,9 +29,9 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtils; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSTile.State; import com.android.systemui.qs.external.TileServices; import com.android.systemui.statusbar.phone.ManagedProfileController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index cf2c16dd8664..9bbead46c33b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -35,9 +35,9 @@ import android.widget.Toolbar; import android.widget.Toolbar.OnMenuItemClickListener; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer; +import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSDetailClipper; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; @@ -69,7 +69,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene private Toolbar mToolbar; private boolean mCustomizing; private NotificationsQuickSettingsContainer mNotifQsContainer; - private QSContainer mQsContainer; + private QS mQs; public QSCustomizer(Context context, AttributeSet attrs) { super(new ContextThemeWrapper(context, R.style.edit_theme), attrs); @@ -127,8 +127,8 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mNotifQsContainer = notificationsQsContainer; } - public void setQsContainer(QSContainer qsContainer) { - mQsContainer = qsContainer; + public void setQs(QS qs) { + mQs = qs; } public void show(int x, int y) { @@ -169,7 +169,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene private void setCustomizing(boolean customizing) { mCustomizing = customizing; - mQsContainer.notifyCustomizeChanged(); + mQs.notifyCustomizeChanged(); } public boolean isCustomizing() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 8d7f6ee72850..f2c3e61cfe02 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -40,7 +40,7 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.R; import com.android.systemui.qs.QSIconView; import com.android.systemui.qs.customize.TileAdapter.Holder; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index dc68112c6bbc..28530d7b0cfb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -37,7 +37,7 @@ import android.view.IWindowManager; import android.view.WindowManager; import android.view.WindowManagerGlobal; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index 91a0eb095ff9..342df5eff1fb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -143,6 +143,7 @@ public class TileServiceManager { } public void handleDestroy() { + setBindAllowed(false); mServices.getContext().unregisterReceiver(mUninstallReceiver); mStateManager.handleDestroy(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 6bc94b25aa5a..015a4c0488f3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -306,6 +306,11 @@ public class TileServices extends IQSService.Stub { } } + public void destroy() { + mServices.values().forEach(service -> service.handleDestroy()); + mContext.unregisterReceiver(mRequestListeningReceiver); + } + private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index a980a7f87405..e57cd58fe8fe 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -26,7 +26,7 @@ import android.provider.Settings.Global; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.GlobalSetting; import com.android.systemui.qs.QSTile; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java index d89fbfd3c8df..fc1c1ac05ed0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java @@ -20,8 +20,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Looper; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.RelativeSizeSpan; @@ -35,12 +33,12 @@ import android.widget.Button; import android.widget.Checkable; import android.widget.ImageView; import android.widget.TextView; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.BatteryInfo; import com.android.settingslib.graph.UsageView; import com.android.systemui.BatteryMeterDrawable; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BatteryController; @@ -80,9 +78,9 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll @Override public void setListening(boolean listening) { if (listening) { - mBatteryController.addStateChangedCallback(this); + mBatteryController.addCallback(this); } else { - mBatteryController.removeStateChangedCallback(this); + mBatteryController.removeCallback(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 18bde27fc6b4..f83b27905dae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -29,10 +29,10 @@ import android.widget.Button; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSTile; @@ -67,9 +67,9 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { @Override public void setListening(boolean listening) { if (listening) { - mController.addStateChangedCallback(mCallback); + mController.addCallback(mCallback); } else { - mController.removeStateChangedCallback(mCallback); + mController.removeCallback(mCallback); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 61bad771b6e0..8afa91eb1026 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -26,9 +26,9 @@ import android.view.ViewGroup; import android.widget.Button; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSTile; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 7de883e2505d..1406c9f59a32 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -26,10 +26,10 @@ import android.view.ViewGroup; import android.widget.Button; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSIconView; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.SignalTileView; @@ -68,9 +68,9 @@ public class CellularTile extends QSTile<QSTile.SignalState> { @Override public void setListening(boolean listening) { if (listening) { - mController.addSignalCallback(mSignalCallback); + mController.addCallback(mSignalCallback); } else { - mController.removeSignalCallback(mSignalCallback); + mController.removeCallback(mSignalCallback); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 5ae7a767aaea..77f063dfc2eb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -22,7 +22,7 @@ import android.provider.Settings.Secure; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.SecureSetting; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index aabafe162f0c..65432dc9ec31 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -19,7 +19,7 @@ import android.content.Intent; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.qs.QSTile; @@ -44,9 +44,9 @@ public class DataSaverTile extends QSTile<QSTile.BooleanState> implements @Override public void setListening(boolean listening) { if (listening) { - mDataSaverController.addListener(this); + mDataSaverController.addCallback(this); } else { - mDataSaverController.remListener(this); + mDataSaverController.removeCallback(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index ec4ab51e0d1e..198375d391e7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -33,11 +33,11 @@ import android.widget.Switch; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysUIToast; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.volume.ZenModePanel; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 0aa723edfb31..5b1638fe9898 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -25,7 +25,7 @@ import android.text.style.ForegroundColorSpan; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.FlashlightController; @@ -45,13 +45,13 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements public FlashlightTile(Host host) { super(host); mFlashlightController = host.getFlashlightController(); - mFlashlightController.addListener(this); + mFlashlightController.addCallback(this); } @Override protected void handleDestroy() { super.handleDestroy(); - mFlashlightController.removeListener(this); + mFlashlightController.removeCallback(this); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 016c4b70f485..dcee659a0463 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -16,8 +16,6 @@ package com.android.systemui.qs.tiles; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.UserManager; @@ -29,7 +27,7 @@ import android.text.style.ForegroundColorSpan; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.GlobalSetting; import com.android.systemui.qs.QSTile; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java index 2a2cc46cb98c..f9688169d795 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java @@ -30,7 +30,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.qs.QSTile; import java.util.Arrays; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index 5b5ecae3d423..8a9a696481e7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -23,7 +23,7 @@ import android.provider.Settings; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -58,10 +58,10 @@ public class LocationTile extends QSTile<QSTile.BooleanState> { @Override public void setListening(boolean listening) { if (listening) { - mController.addSettingsChangedCallback(mCallback); + mController.addCallback(mCallback); mKeyguard.addCallback(mCallback); } else { - mController.removeSettingsChangedCallback(mCallback); + mController.removeCallback(mCallback); mKeyguard.removeCallback(mCallback); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index c02e5aee9ccf..10fde3042ce4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -23,7 +23,7 @@ import android.widget.Switch; import com.android.internal.app.NightDisplayController; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 499eb50e9992..cec5f15ddd0d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -24,7 +24,7 @@ import android.provider.Settings; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.RotationLockController; @@ -61,9 +61,9 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> { public void setListening(boolean listening) { if (mController == null) return; if (listening) { - mController.addRotationLockControllerCallback(mCallback); + mController.addCallback(mCallback); } else { - mController.removeRotationLockControllerCallback(mCallback); + mController.removeCallback(mCallback); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index cd09231ca002..91d38bd075bf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -24,7 +24,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.R; import com.android.systemui.qs.PseudoGridView; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java index b5fbfe05d368..246c23e20f48 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java @@ -21,8 +21,8 @@ import android.graphics.drawable.Drawable; import android.provider.Settings; import android.util.Pair; -import com.android.internal.logging.MetricsProto.MetricsEvent; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -67,9 +67,9 @@ public class UserTile extends QSTile<QSTile.State> implements UserInfoController @Override public void setListening(boolean listening) { if (listening) { - mUserInfoController.addListener(this); + mUserInfoController.addCallback(this); } else { - mUserInfoController.remListener(this); + mUserInfoController.removeCallback(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 27306fcfcd00..3876c88ce4a2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -28,10 +28,10 @@ import android.widget.Button; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.wifi.AccessPoint; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSIconView; @@ -70,9 +70,9 @@ public class WifiTile extends QSTile<QSTile.SignalState> { @Override public void setListening(boolean listening) { if (listening) { - mController.addSignalCallback(mSignalCallback); + mController.addCallback(mSignalCallback); } else { - mController.removeSignalCallback(mSignalCallback); + mController.removeCallback(mSignalCallback); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 459e8ece569e..ce7fbd368cba 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -21,7 +21,7 @@ import android.provider.Settings; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.phone.ManagedProfileController; diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 27fcf2a5aba7..7655e6cee85b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -41,7 +41,7 @@ import android.view.Display; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -57,6 +57,7 @@ import com.android.systemui.recents.events.component.ShowUserToastEvent; import com.android.systemui.recents.events.ui.RecentsDrawnEvent; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.RecentsTaskLoader; +import com.android.systemui.recents.grid.RecentsGridImpl; import com.android.systemui.recents.tv.RecentsTvImpl; import com.android.systemui.stackdivider.Divider; @@ -83,6 +84,7 @@ public class Recents extends SystemUI static { RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY); RECENTS_ACTIVITIES.add(RecentsTvImpl.RECENTS_TV_ACTIVITY); + RECENTS_ACTIVITIES.add(RecentsGridImpl.RECENTS_MOSAIC_ACTIVITY); } // Purely for experimentation @@ -205,6 +207,8 @@ public class Recents extends SystemUI getSystemService(Context.UI_MODE_SERVICE); if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) { mImpl = new RecentsTvImpl(mContext); + } else if (SystemProperties.getBoolean("ro.recents.grid", false) == true) { + mImpl = new RecentsGridImpl(mContext); } else { mImpl = new RecentsImpl(mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index ec99d20ffdb3..af1823c88da0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -40,7 +40,7 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.keyguard.LatencyTracker; diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index b961055c6fed..cf75c4f50bb6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -19,7 +19,6 @@ package com.android.systemui.recents; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -117,7 +116,7 @@ public class ScreenPinningRequest implements View.OnClickListener { public void onClick(View v) { if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) { try { - ActivityManagerNative.getDefault().startSystemLockTaskMode(taskId); + ActivityManager.getService().startSystemLockTaskMode(taskId); } catch (RemoteException e) {} } clearPrompt(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java new file mode 100644 index 000000000000..e1e654d58be7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.recents.grid; + +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.R; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsActivity; +import com.android.systemui.recents.RecentsActivityLaunchState; +import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.RecentsImpl; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.ConfigurationChangedEvent; +import com.android.systemui.recents.events.activity.HideRecentsEvent; +import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent; +import com.android.systemui.recents.events.activity.LaunchTaskEvent; +import com.android.systemui.recents.events.activity.ToggleRecentsEvent; +import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; +import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent; +import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; +import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; +import com.android.systemui.recents.events.ui.DismissTaskViewEvent; +import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; +import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.recents.model.RecentsTaskLoadPlan; +import com.android.systemui.recents.model.RecentsTaskLoader; +import com.android.systemui.recents.model.Task; +import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.recents.views.TaskView; + +import java.util.ArrayList; +import java.util.List; + +/** + * The main grid recents activity started by the RecentsImpl. + */ +public class RecentsGridActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { + private final static String TAG = "RecentsGridActivity"; + + private TaskStack mTaskStack; + private List<Task> mTasks = new ArrayList<>(); + private List<TaskView> mTaskViews = new ArrayList<>(); + private FrameLayout mRecentsView; + private TextView mEmptyView; + private View mClearAllButton; + private int mLastDisplayOrientation = Configuration.ORIENTATION_UNDEFINED; + private int mLastDisplayDensity; + private Rect mDisplayRect = new Rect(); + private LayoutInflater mInflater; + private boolean mTouchExplorationEnabled; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.recents_grid); + SystemServicesProxy ssp = Recents.getSystemServices(); + + mInflater = LayoutInflater.from(this); + Configuration appConfiguration = Utilities.getAppConfiguration(this); + mDisplayRect = ssp.getDisplayRect(); + mLastDisplayOrientation = appConfiguration.orientation; + mLastDisplayDensity = appConfiguration.densityDpi; + mTouchExplorationEnabled = ssp.isTouchExplorationEnabled(); + + mRecentsView = (FrameLayout) findViewById(R.id.recents_view); + mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + getWindow().getAttributes().privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; + LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container); + mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false); + mClearAllButton = findViewById(R.id.button); + + FrameLayout.LayoutParams emptyViewLayoutParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); + emptyViewLayoutParams.gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL; + mEmptyView.setLayoutParams(emptyViewLayoutParams); + mRecentsView.addView(mEmptyView); + + mClearAllButton.setVisibility(View.VISIBLE); + LinearLayout.LayoutParams lp = + (LinearLayout.LayoutParams) mClearAllButton.getLayoutParams(); + lp.gravity = Gravity.END; + + mClearAllButton.setOnClickListener(v -> { + EventBus.getDefault().send(new DismissAllTaskViewsEvent()); + }); + + mRecentsView.setOnClickListener(v -> { + EventBus.getDefault().send(new HideRecentsEvent( + false /* triggeredFromAltTab */, false /* triggeredFromHomeKey */)); + }); + + EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY); + } + + private TaskView createView() { + return (TaskView) mInflater.inflate(R.layout.recents_task_view, mRecentsView, false); + } + + private void removeTaskViews() { + for (View taskView : mTaskViews) { + ViewGroup parent = (ViewGroup) taskView.getParent(); + if (parent != null) { + parent.removeView(taskView); + } + } + } + + private void clearTaskViews() { + removeTaskViews(); + mTaskViews.clear(); + } + + private TaskView getChildViewForTask(Task task) { + for (TaskView tv : mTaskViews) { + if (tv.getTask() == task) { + return tv; + } + } + return null; + } + + private void updateControlVisibility() { + boolean empty = (mTasks.size() == 0); + mClearAllButton.setVisibility(empty ? View.INVISIBLE : View.VISIBLE); + mEmptyView.setVisibility(empty ? View.VISIBLE : View.INVISIBLE); + if (empty) { + mEmptyView.bringToFront(); + } + } + + private void updateRecentsTasks() { + RecentsTaskLoader loader = Recents.getTaskLoader(); + RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan(); + if (plan == null) { + plan = loader.createLoadPlan(this); + } + RecentsConfiguration config = Recents.getConfiguration(); + RecentsActivityLaunchState launchState = config.getLaunchState(); + if (!plan.hasTasks()) { + loader.preloadTasks(plan, -1, !launchState.launchedFromHome); + } + int numVisibleTasks = 9; + mTaskStack = plan.getTaskStack(); + RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); + loadOpts.runningTaskId = launchState.launchedToTaskId; + loadOpts.numVisibleTasks = numVisibleTasks; + loadOpts.numVisibleTaskThumbnails = numVisibleTasks; + loader.loadTasks(this, plan, loadOpts); + + mTasks = mTaskStack.getStackTasks(); + + updateControlVisibility(); + + clearTaskViews(); + for (int i = 0; i < mTasks.size(); i++) { + Task task = mTasks.get(i); + TaskView taskView = createView(); + taskView.onTaskBound(task, mTouchExplorationEnabled, mLastDisplayOrientation, + mDisplayRect); + Recents.getTaskLoader().loadTaskData(task); + taskView.setTouchEnabled(true); + // Show dismiss button right away. + taskView.startNoUserInteractionAnimation(); + mTaskViews.add(taskView); + } + } + + @Override + protected void onStart() { + super.onStart(); + EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true)); + mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); + } + + @Override + public void onResume() { + super.onResume(); + updateRecentsTasks(); + } + + @Override + protected void onStop() { + super.onStop(); + EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false)); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + public void onBackPressed() { + // Back behaves like the recents button so just trigger a toggle event. + EventBus.getDefault().send(new ToggleRecentsEvent()); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Notify of the config change. + Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this); + mDisplayRect = Recents.getSystemServices().getDisplayRect(); + mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); + mRecentsView.requestLayout(); + int numStackTasks = mTaskStack.getStackTaskCount(); + EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */, + mLastDisplayOrientation != newDeviceConfiguration.orientation, + mLastDisplayDensity != newDeviceConfiguration.densityDpi, numStackTasks > 0)); + mLastDisplayOrientation = newDeviceConfiguration.orientation; + mLastDisplayDensity = newDeviceConfiguration.densityDpi; + } + + @Override + public boolean onPreDraw() { + mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this); + int width = mRecentsView.getWidth(); + int height = mRecentsView.getHeight(); + + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + mTasks.size(), width, height, false /* allowLineOfThree */, 30 /* padding */); + removeTaskViews(); + for (int i = 0; i < rects.size(); i++) { + Rect rect = rects.get(i); + // We keep the same ordering in the model as other Recents flavors (older tasks are + // first in the stack) so that the logic can be similar, but we reverse the order + // when placing views on the screen so that most recent tasks are displayed first. + View taskView = mTaskViews.get(rects.size() - 1 - i); + taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height())); + taskView.setTranslationX(rect.left); + taskView.setTranslationY(rect.top); + mRecentsView.addView(taskView); + } + return true; + } + + void dismissRecentsToHome() { + Intent startMain = new Intent(Intent.ACTION_MAIN); + startMain.addCategory(Intent.CATEGORY_HOME); + startActivity(startMain); + } + + /** Launches the task that recents was launched from if possible. */ + boolean launchPreviousTask() { + if (mRecentsView != null) { + Task task = mTaskStack.getLaunchTarget(); + if (task != null) { + TaskView taskView = getChildViewForTask(task); + EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, + INVALID_STACK_ID, false)); + return true; + } + } + return false; + } + + /** Dismisses recents back to the launch target task. */ + boolean dismissRecentsToLaunchTargetTaskOrHome() { + SystemServicesProxy ssp = Recents.getSystemServices(); + if (ssp.isRecentsActivityVisible()) { + // If we can launch the task that Recents was launched from, do that, otherwise go home. + if (launchPreviousTask()) return true; + dismissRecentsToHome(); + } + return false; + } + + /**** EventBus events ****/ + + public final void onBusEvent(HideRecentsEvent event) { + if (event.triggeredFromAltTab) { + dismissRecentsToLaunchTargetTaskOrHome(); + } else if (event.triggeredFromHomeKey) { + dismissRecentsToHome(); + } else { + // Fall through tap on the background view but not on any of the tasks. + dismissRecentsToHome(); + } + } + + public final void onBusEvent(ToggleRecentsEvent event) { + dismissRecentsToLaunchTargetTaskOrHome(); + } + + public final void onBusEvent(DismissTaskViewEvent event) { + int taskIndex = mTaskViews.indexOf(event.taskView); + if (taskIndex != -1) { + mTasks.remove(taskIndex); + ((ViewGroup) event.taskView.getParent()).removeView(event.taskView); + mTaskViews.remove(taskIndex); + EventBus.getDefault().send( + new TaskViewDismissedEvent(event.taskView.getTask(), event.taskView, null)); + } + } + + public final void onBusEvent(TaskViewDismissedEvent event) { + mRecentsView.announceForAccessibility(this.getString( + R.string.accessibility_recents_item_dismissed, event.task.title)); + updateControlVisibility(); + + EventBus.getDefault().send(new DeleteTaskDataEvent(event.task)); + + MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS, + event.task.key.getComponent().toString()); + } + + public final void onBusEvent(DeleteTaskDataEvent event) { + // Remove any stored data from the loader. + RecentsTaskLoader loader = Recents.getTaskLoader(); + loader.deleteTaskData(event.task, false); + + // Remove the task from activity manager. + SystemServicesProxy ssp = Recents.getSystemServices(); + ssp.removeTask(event.task.key.id); + } + + public final void onBusEvent(final DismissAllTaskViewsEvent event) { + // Keep track of the tasks which will have their data removed. + ArrayList<Task> tasks = new ArrayList<>(mTaskStack.getStackTasks()); + mRecentsView.announceForAccessibility(this.getString( + R.string.accessibility_recents_all_items_dismissed)); + mTaskStack.removeAllTasks(); + for (int i = tasks.size() - 1; i >= 0; i--) { + EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i))); + } + mTasks = new ArrayList<>(); + updateRecentsTasks(); + + MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS_ALL); + } + + public final void onBusEvent(AllTaskViewsDismissedEvent event) { + SystemServicesProxy ssp = Recents.getSystemServices(); + if (!ssp.hasDockedTask()) { + dismissRecentsToHome(); + } + } + + public final void onBusEvent(LaunchNextTaskRequestEvent event) { + if (mTaskStack.getTaskCount() > 0) { + Task launchTask = mTaskStack.getNextLaunchTarget(); + TaskView launchTaskView = getChildViewForTask(launchTask); + if (launchTaskView != null) { + EventBus.getDefault().send(new LaunchTaskEvent(launchTaskView, + launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */)); + MetricsLogger.action(this, MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK, + launchTask.key.getComponent().toString()); + return; + } + } + // We couldn't find a matching task view, or there are no tasks. Just hide recents back + // to home. + EventBus.getDefault().send(new HideRecentsEvent(false, true)); + } + + public final void onBusEvent(LaunchTaskEvent event) { + startActivity(event.task.key.baseIntent); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridImpl.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridImpl.java new file mode 100644 index 000000000000..41acaa0a619a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.recents.grid; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; + +import com.android.systemui.recents.RecentsImpl; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; + +public class RecentsGridImpl extends RecentsImpl { + public static final String RECENTS_MOSAIC_ACTIVITY = + "com.android.systemui.recents.grid.RecentsGridActivity"; + + public RecentsGridImpl(Context context) { + super(context); + } + + @Override + protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask, + boolean isHomeStackVisible, boolean animate, int growTarget) { + Intent intent = new Intent(); + intent.setClassName(RECENTS_PACKAGE, RECENTS_MOSAIC_ACTIVITY); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_TASK_ON_HOME); + + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + EventBus.getDefault().send(new RecentsActivityStartingEvent()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java new file mode 100644 index 000000000000..057aa5497bf4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.recents.grid; + +import android.graphics.Rect; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +class TaskGridLayoutAlgorithm { + + private static final String TAG = "TaskGridLayoutAlgorithm"; + + static List<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight, + boolean allowLineOfThree, int padding) { + return getRectsForTaskCount(count, containerWidth, containerHeight, allowLineOfThree, + padding, null); + } + + static List<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight, + boolean allowLineOfThree, int padding, Rect preCalculatedTile) { + int singleLineMaxCount = allowLineOfThree ? 3 : 2; + List<Rect> rects = new ArrayList<>(count); + boolean landscape = (containerWidth > containerHeight); + + // We support at most 9 tasks in this layout. + count = Math.min(count, 9); + + if (count == 0) { + return rects; + } + if (count <= singleLineMaxCount) { + if (landscape) { + // Single line. + int taskWidth = 0; + int emptySpace = 0; + if (preCalculatedTile != null) { + taskWidth = preCalculatedTile.width(); + emptySpace = containerWidth - (count * taskWidth) - (count - 1) * padding; + } else { + // Divide available space in equal parts. + taskWidth = (containerWidth - (count - 1) * padding) / count; + } + for (int i = 0; i < count; i++) { + int left = emptySpace / 2 + i * taskWidth + i * padding; + rects.add(new Rect(left, 0, left + taskWidth, containerHeight)); + } + } else { + // Single column. Divide available space in equal parts. + int taskHeight = (containerHeight - (count - 1) * padding) / count; + for (int i = 0; i < count; i++) { + int top = i * taskHeight + i * padding; + rects.add(new Rect(0, top, containerWidth, top + taskHeight)); + } + } + } else if (count < 7) { + // Two lines. + int lineHeight = (containerHeight - padding) / 2; + int lineTaskCount = (int) Math.ceil((double) count / 2); + List<Rect> rectsA = getRectsForTaskCount( + lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, + null); + List<Rect> rectsB = getRectsForTaskCount( + count - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, + padding, rectsA.get(0)); + for (Rect rect : rectsB) { + rect.offset(0, lineHeight + padding); + } + rects.addAll(rectsA); + rects.addAll(rectsB); + } else { + // Three lines. + int lineHeight = (containerHeight - 2 * padding) / 3; + int lineTaskCount = (int) Math.ceil((double) count / 3); + List<Rect> rectsA = getRectsForTaskCount( + lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, null); + List<Rect> rectsB = getRectsForTaskCount( + lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, + rectsA.get(0)); + List<Rect> rectsC = getRectsForTaskCount( + count - (2 * lineTaskCount), containerWidth, lineHeight, + true /* allowLineOfThree */, padding, rectsA.get(0)); + for (Rect rect : rectsB) { + rect.offset(0, lineHeight + padding); + } + for (Rect rect : rectsC) { + rect.offset(0, 2 * (lineHeight + padding)); + } + rects.addAll(rectsA); + rects.addAll(rectsB); + rects.addAll(rectsC); + } + return rects; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 11a4f64726b9..2272a728cc54 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -25,7 +25,6 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityManager; @@ -85,7 +84,6 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.RecentsImpl; import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.tv.RecentsTvImpl; import com.android.systemui.recents.model.ThumbnailData; import java.io.IOException; @@ -158,7 +156,7 @@ public class SystemServicesProxy { /** * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from - * ActivityManagerNative. + * ActivityManagerService. * This simply passes callbacks to listeners through {@link H}. * */ private android.app.TaskStackListener mTaskStackListener = new android.app.TaskStackListener() { @@ -208,7 +206,7 @@ public class SystemServicesProxy { private SystemServicesProxy(Context context) { mAccm = AccessibilityManager.getInstance(context); mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - mIam = ActivityManagerNative.getDefault(); + mIam = ActivityManager.getService(); mPm = context.getPackageManager(); mIpm = AppGlobals.getPackageManager(); mAssistUtils = new AssistUtils(context); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 745f5a5a773e..178cb9f890c2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -849,6 +849,24 @@ public class TaskStack { return null; } + /** + * Returns the task in stack tasks which should be launched next if Recents are toggled + * again, or null if there is no task to be launched. + */ + public Task getNextLaunchTarget() { + int taskCount = getTaskCount(); + if (taskCount == 0) { + return null; + } + int launchTaskIndex = indexOfStackTask(getLaunchTarget()); + if (launchTaskIndex != -1) { + launchTaskIndex = Math.max(0, launchTaskIndex - 1); + } else { + launchTaskIndex = getTaskCount() - 1; + } + return getStackTasks().get(launchTaskIndex); + } + /** Returns the index of this task in this current task stack */ public int indexOfStackTask(Task t) { return mStackTaskList.indexOf(t); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index febeacb3bcf0..3c7012a16dfc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -43,7 +43,7 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 936354e98998..8c94c3578e96 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -47,7 +47,7 @@ import android.widget.FrameLayout; import android.widget.ScrollView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; @@ -1683,17 +1683,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return; } - int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget()); - if (launchTaskIndex != -1) { - launchTaskIndex = Math.max(0, launchTaskIndex - 1); - } else { - launchTaskIndex = mStack.getTaskCount() - 1; - } - if (launchTaskIndex != -1) { + final Task launchTask = mStack.getNextLaunchTarget(); + if (launchTask != null) { // Stop all animations cancelAllTaskViewAnimations(); - final Task launchTask = mStack.getStackTasks().get(launchTaskIndex); float curScroll = mStackScroller.getStackScroll(); float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask); float absScrollDiff = Math.abs(targetScroll - curScroll); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index d44aa844003f..71f559be6775 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -34,7 +34,7 @@ import android.view.ViewParent; import android.view.animation.Interpolator; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.SwipeHelper; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 99d98bcd3f1d..de7def6c95c9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -39,7 +39,7 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; @@ -362,12 +362,12 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks } /** Enables/disables handling touch on this task view. */ - void setTouchEnabled(boolean enabled) { + public void setTouchEnabled(boolean enabled) { setOnClickListener(enabled ? this : null); } /** Animates this task view if the user does not interact with the stack after a certain time. */ - void startNoUserInteractionAnimation() { + public void startNoUserInteractionAnimation() { mHeaderView.startNoUserInteractionAnimation(); } @@ -668,10 +668,16 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks @Override public boolean onLongClick(View v) { SystemServicesProxy ssp = Recents.getSystemServices(); - // Since we are clipping the view to the bounds, manually do the hit test + boolean inBounds = false; Rect clipBounds = new Rect(mViewBounds.mClipBounds); - clipBounds.scale(getScaleX()); - boolean inBounds = clipBounds.contains(mDownTouchPos.x, mDownTouchPos.y); + if (!clipBounds.isEmpty()) { + // If we are clipping the view to the bounds, manually do the hit test. + clipBounds.scale(getScaleX()); + inBounds = clipBounds.contains(mDownTouchPos.x, mDownTouchPos.y); + } else { + // Otherwise just make sure we're within the view's bounds. + inBounds = mDownTouchPos.x <= getWidth() && mDownTouchPos.y <= getHeight(); + } if (v == this && inBounds && !ssp.hasDockedTask()) { // Start listening for drag events setClipViewInStack(false); diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 3ed26984c809..e8039c35bb4f 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -33,7 +33,7 @@ import android.provider.Settings; import android.widget.ImageView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java index 803fe4809322..901d47d6cde8 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java @@ -25,7 +25,7 @@ import android.view.WindowManager; import android.widget.ImageView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; /** A dialog that provides controls for adjusting the screen brightness. */ 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/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java index 15d26f9a7a0c..19eefec2ad8b 100644 --- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java @@ -18,7 +18,6 @@ package com.android.systemui.shortcut; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; @@ -35,7 +34,7 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.settingslib.accessibility.AccessibilityUtils; import com.android.systemui.R; @@ -59,7 +58,7 @@ public class ShortcutKeyDispatcher extends SystemUI private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this); private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); - private IActivityManager mActivityManager = ActivityManagerNative.getDefault(); + private IActivityManager mActivityManager = ActivityManager.getService(); protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE; protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 4e34bbc11453..47d2def0cf63 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -54,7 +54,7 @@ import android.view.animation.PathInterpolator; import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index ef32f7e8777e..c24512649c2f 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -19,7 +19,7 @@ package com.android.systemui.stackdivider; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.view.WindowManager.DOCKED_INVALID; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.graphics.Rect; import android.os.RemoteException; import android.util.Log; @@ -72,7 +72,7 @@ public class WindowManagerProxy { mTmpRect5.set(mTempOtherInsetRect); } try { - ActivityManagerNative.getDefault() + ActivityManager.getService() .resizeDockedStack(mTmpRect1, mTmpRect2.isEmpty() ? null : mTmpRect2, mTmpRect3.isEmpty() ? null : mTmpRect3, @@ -88,7 +88,7 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManagerNative.getDefault().moveTasksToFullscreenStack( + ActivityManager.getService().moveTasksToFullscreenStack( DOCKED_STACK_ID, false /* onTop */); } catch (RemoteException e) { Log.w(TAG, "Failed to remove stack: " + e); @@ -100,7 +100,7 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManagerNative.getDefault().resizeStack( + ActivityManager.getService().resizeStack( DOCKED_STACK_ID, null, true, true, false, -1); } catch (RemoteException e) { Log.w(TAG, "Failed to resize stack: " + e); @@ -124,7 +124,7 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManagerNative.getDefault().swapDockedAndFullscreenStack(); + ActivityManager.getService().swapDockedAndFullscreenStack(); } catch (RemoteException e) { Log.w(TAG, "Failed to resize stack: " + e); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 23acb1b1ce41..19e511cff228 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -20,7 +20,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.app.ActivityManager; import android.app.ActivityManager.StackId; -import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.app.KeyguardManager; import android.app.Notification; @@ -87,7 +86,7 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.widget.LockPatternUtils; @@ -334,7 +333,7 @@ public abstract class BaseStatusBar extends SystemUI implements // the user switches to home. We know it is safe to do at this // point, so make sure new activity switches are now allowed. try { - ActivityManagerNative.getDefault().resumeAppSwitches(); + ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } final boolean isActivity = pendingIntent.isActivity(); @@ -346,7 +345,7 @@ public abstract class BaseStatusBar extends SystemUI implements @Override public boolean onDismiss() { try { - ActivityManagerNative.getDefault().resumeAppSwitches(); + ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } @@ -515,7 +514,7 @@ public abstract class BaseStatusBar extends SystemUI implements } else if (Intent.ACTION_USER_PRESENT.equals(action)) { List<ActivityManager.RecentTaskInfo> recentTask = null; try { - recentTask = ActivityManagerNative.getDefault().getRecentTasks(1, + recentTask = ActivityManager.getService().getRecentTasks(1, ActivityManager.RECENT_WITH_EXCLUDED | ActivityManager.RECENT_INCLUDE_PROFILES, mCurrentUserId).getList(); @@ -1321,7 +1320,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected void sendCloseSystemWindows(String reason) { try { - ActivityManagerNative.getDefault().closeSystemDialogs(reason); + ActivityManager.getService().closeSystemDialogs(reason); } catch (RemoteException e) { } } @@ -1820,7 +1819,7 @@ public abstract class BaseStatusBar extends SystemUI implements // won't have permission to immediately start an activity after // the user switches to home. We know it is safe to do at this // point, so make sure new activity switches are now allowed. - ActivityManagerNative.getDefault().resumeAppSwitches(); + ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } try { @@ -1924,7 +1923,7 @@ public abstract class BaseStatusBar extends SystemUI implements // won't have permission to immediately start an activity after // the user switches to home. We know it is safe to do at this // point, so make sure new activity switches are now allowed. - ActivityManagerNative.getDefault().resumeAppSwitches(); + ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } if (intent != null) { @@ -1938,7 +1937,7 @@ public abstract class BaseStatusBar extends SystemUI implements && mKeyguardManager.isDeviceLocked(userId)) { boolean canBypass = false; try { - canBypass = ActivityManagerNative.getDefault() + canBypass = ActivityManager.getService() .canBypassWorkChallenge(intent); } catch (RemoteException e) { } @@ -2058,7 +2057,7 @@ public abstract class BaseStatusBar extends SystemUI implements Intent.EXTRA_INTENT, callBackPendingIntent.getIntentSender()); try { - ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent); + ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent); } catch (RemoteException ex) { // ignore } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index caf5447d9d26..5173176ffa8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -43,7 +43,7 @@ import android.widget.Chronometer; import android.widget.ImageView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.NotificationColorUtil; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index f4387629b8b3..f43fc4065766 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -59,7 +59,7 @@ import android.widget.TextView; import com.android.internal.app.AssistUtils; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.recents.Recents; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index b10fb3133d98..bb327eff5c40 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -43,7 +43,7 @@ import android.widget.SeekBar; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.Utils; import com.android.systemui.Interpolators; import com.android.systemui.R; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 74caa5326f83..68d5cd41b363 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -151,8 +151,8 @@ public class SignalClusterView mBlockEthernet = blockEthernet; mBlockWifi = blockWifi; // Re-register to get new callbacks. - mNC.removeSignalCallback(this); - mNC.addSignalCallback(this); + mNC.removeCallback(this); + mNC.addCallback(this); } } @@ -224,7 +224,7 @@ public class SignalClusterView apply(); applyIconTint(); - mNC.addSignalCallback(this); + mNC.addCallback(this); } @Override @@ -232,7 +232,7 @@ public class SignalClusterView mMobileSignalGroup.removeAllViews(); TunerService.get(mContext).removeTunable(this); mSC.removeCallback(this); - mNC.removeSignalCallback(this); + mNC.removeCallback(this); super.onDetachedFromWindow(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java index 497720265d7c..fc39648b7ac0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java @@ -99,7 +99,7 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo } @Override - public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { + public void addCallback(BatteryController.BatteryStateChangeCallback cb) { mChangeCallbacks.add(cb); // There is no way to know if the phone is plugged in or charging via bluetooth, so pass @@ -109,7 +109,7 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo } @Override - public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { + public void removeCallback(BatteryController.BatteryStateChangeCallback cb) { mChangeCallbacks.remove(cb); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java index baff6806dc73..1c8c317790ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java @@ -30,7 +30,7 @@ import android.view.View; import android.widget.LinearLayout; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.ActivityStarter; +import com.android.systemui.plugins.qs.QS.ActivityStarter; import java.net.URISyntaxException; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 8a5a8a04882e..dd5832b886ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.car; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.content.BroadcastReceiver; import android.content.Context; @@ -256,7 +255,7 @@ public class CarStatusBar extends PhoneStatusBar implements private int startActivityWithOptions(Intent intent, Bundle options) { int result = ActivityManager.START_CANCELED; try { - result = ActivityManagerNative.getDefault().startActivityAsUser(null /* caller */, + result = ActivityManager.getService().startActivityAsUser(null /* caller */, mContext.getBasePackageName(), intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java index 66030b935f07..a3e1b3ac489f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java @@ -94,12 +94,12 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT); mContext.registerReceiver(this, filter); - mController.addStateChangedCallback(this); + mController.addCallback(this); } public void stopListening() { mContext.unregisterReceiver(this); - mController.removeStateChangedCallback(this); + mController.removeCallback(this); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index b74247960fc7..a01116239ed4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -42,7 +42,7 @@ public class AutoTileManager { host.getHotspotController().addCallback(mHotspotCallback); } if (!Prefs.getBoolean(context, Key.QS_DATA_SAVER_ADDED, false)) { - host.getNetworkController().getDataSaverController().addListener(mDataSaverListener); + host.getNetworkController().getDataSaverController().addCallback(mDataSaverListener); } if (!Prefs.getBoolean(context, Key.QS_INVERT_COLORS_ADDED, false)) { mColorsSetting = new SecureSetting(mContext, mHandler, @@ -69,7 +69,10 @@ public class AutoTileManager { } public void destroy() { - // TODO: Remove any registered listeners. + mColorsSetting.setListening(false); + mHost.getHotspotController().removeCallback(mHotspotCallback); + mHost.getNetworkController().getDataSaverController().removeCallback(mDataSaverListener); + mHost.getManagedProfileController().removeCallback(mProfileCallback); } private final ManagedProfileController.Callback mProfileCallback = @@ -105,7 +108,7 @@ public class AutoTileManager { mHandler.post(new Runnable() { @Override public void run() { - mHost.getNetworkController().getDataSaverController().remListener( + mHost.getNetworkController().getDataSaverController().removeCallback( mDataSaverListener); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index dfb06d787197..89defec6f94c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -20,7 +20,6 @@ import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; @@ -66,7 +65,7 @@ import com.android.systemui.plugins.IntentButtonProvider.IntentButton; import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; -import com.android.systemui.plugins.qs.QSContainer.ActivityStarter; +import com.android.systemui.plugins.qs.QS.ActivityStarter; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -363,7 +362,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); if (dpm != null && mPhoneStatusBar != null) { try { - final int userId = ActivityManagerNative.getDefault().getCurrentUser().id; + final int userId = ActivityManager.getService().getCurrentUser().id; final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId); final boolean disabledBecauseKeyguardSecure = (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0 @@ -487,7 +486,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL o.setRotationAnimationHint( WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); try { - result = ActivityManagerNative.getDefault().startActivityAsUser( + result = ActivityManager.getService().startActivityAsUser( null, getContext().getBasePackageName(), intent, intent.resolveTypeIfNeeded(getContext().getContentResolver()), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index d94def9129bb..e4c778c867df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -190,9 +190,9 @@ public class KeyguardStatusBarView extends RelativeLayout } mBatteryListening = listening; if (mBatteryListening) { - mBatteryController.addStateChangedCallback(this); + mBatteryController.addCallback(this); } else { - mBatteryController.removeStateChangedCallback(this); + mBatteryController.removeCallback(this); } } @@ -214,7 +214,7 @@ public class KeyguardStatusBarView extends RelativeLayout } public void setUserInfoController(UserInfoController userInfoController) { - userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() { + userInfoController.addCallback(new UserInfoController.OnUserInfoChangedListener() { @Override public void onUserInfoChanged(String name, Drawable picture, String userAccount) { mMultiUserAvatar.setImageDrawable(picture); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java index df4566b28d8b..dd7f3cc62fa4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java @@ -46,7 +46,7 @@ public class LightStatusBarController implements BatteryController.BatteryStateC BatteryController batteryController) { mIconController = iconController; mBatteryController = batteryController; - batteryController.addStateChangedCallback(this); + batteryController.addCallback(this); } public void setFingerprintUnlockController( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java index 951b09681c0b..1a46815c99e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java @@ -24,11 +24,14 @@ import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import com.android.systemui.statusbar.phone.ManagedProfileController.Callback; +import com.android.systemui.statusbar.policy.CallbackController; + import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -public class ManagedProfileController { +public class ManagedProfileController implements CallbackController<Callback> { private final List<Callback> mCallbacks = new ArrayList<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index af9454ceab13..4d4f9d285534 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -30,7 +30,7 @@ import android.widget.Button; import android.widget.FrameLayout; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSPanel; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserSwitcherController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index 0f800bb61de7..228e8ea843b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -27,7 +27,7 @@ import android.view.View; import android.view.ViewConfiguration; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.systemui.R; import com.android.systemui.RecentsComponent; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index df167e66aa5a..97df23709c45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -21,7 +21,7 @@ import android.animation.LayoutTransition.TransitionListener; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.StatusBarManager; import android.content.Context; import android.content.res.Configuration; @@ -422,7 +422,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav private boolean inLockTask() { try { - return ActivityManagerNative.getDefault().isInLockTaskMode(); + return ActivityManager.getService().isInLockTaskMode(); } catch (RemoteException e) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index cda0bfee88c2..068631d4c1ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.ActivityManager; +import android.app.Fragment; import android.app.StatusBarManager; import android.content.Context; import android.content.pm.ResolveInfo; @@ -34,6 +35,7 @@ import android.util.MathUtils; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; +import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; @@ -42,15 +44,15 @@ import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.keyguard.KeyguardStatusView; -import com.android.systemui.AutoReinflateContainer; -import com.android.systemui.AutoReinflateContainer.InflateListener; import com.android.systemui.DejankUtils; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; -import com.android.systemui.plugins.qs.QSContainer; +import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.fragments.FragmentHostManager.FragmentListener; +import com.android.systemui.plugins.qs.QS; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -70,7 +72,7 @@ public class NotificationPanelView extends PanelView implements ExpandableView.OnHeightChangedListener, View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener, - HeadsUpManager.OnHeadsUpChangedListener, QSContainer.HeightListener { + HeadsUpManager.OnHeadsUpChangedListener, QS.HeightListener { private static final boolean DEBUG = false; @@ -92,8 +94,8 @@ public class NotificationPanelView extends PanelView implements private KeyguardAffordanceHelper mAfforanceHelper; private KeyguardUserSwitcher mKeyguardUserSwitcher; private KeyguardStatusBarView mKeyguardStatusBar; - protected QSContainer mQsContainer; - private AutoReinflateContainer mQsAutoReinflateContainer; + private QS mQs; + private FrameLayout mQsFrame; private KeyguardStatusView mKeyguardStatusView; private TextView mClockView; private View mReserveNotificationSpace; @@ -236,31 +238,19 @@ public class NotificationPanelView extends PanelView implements mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper); mLastOrientation = getResources().getConfiguration().orientation; - mQsAutoReinflateContainer = - (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container); - mQsAutoReinflateContainer.addInflateListener(new InflateListener() { - @Override - public void onInflated(View v) { - mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container); - mQsContainer.setPanelView(NotificationPanelView.this); - mQsContainer.getHeader().getExpandView() - .setOnClickListener(NotificationPanelView.this); - - // recompute internal state when qspanel height changes - mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - final int height = bottom - top; - final int oldHeight = oldBottom - oldTop; - if (height != oldHeight) { - onQsHeightChanged(); - } - } - }); - mNotificationStackScroller.setQsContainer(mQsContainer); - } - }); + mQsFrame = (FrameLayout) findViewById(R.id.qs_frame); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener); } @Override @@ -288,12 +278,12 @@ public class NotificationPanelView extends PanelView implements int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width); int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity); FrameLayout.LayoutParams lp = - (FrameLayout.LayoutParams) mQsAutoReinflateContainer.getLayoutParams(); + (FrameLayout.LayoutParams) mQsFrame.getLayoutParams(); if (lp.width != panelWidth) { lp.width = panelWidth; lp.gravity = panelGravity; - mQsAutoReinflateContainer.setLayoutParams(lp); - mQsContainer.post(mUpdateHeader); + mQsFrame.setLayoutParams(lp); + mQs.getView().post(mUpdateHeader); } lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams(); @@ -314,8 +304,10 @@ public class NotificationPanelView extends PanelView implements // Calculate quick setting heights. int oldMaxHeight = mQsMaxExpansionHeight; - mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQsContainer.getQsMinExpansionHeight(); - mQsMaxExpansionHeight = mQsContainer.getDesiredHeight(); + if (mQs != null) { + mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight(); + mQsMaxExpansionHeight = mQs.getDesiredHeight(); + } positionClockAndNotifications(); if (mQsExpanded && mQsFullyExpanded) { mQsExpansionHeight = mQsMaxExpansionHeight; @@ -337,8 +329,8 @@ public class NotificationPanelView extends PanelView implements // the desired height so when closing the QS detail, it stays smaller after the size change // animation is finished but the detail view is still being animated away (this animation // takes longer than the size change animation). - if (mQsSizeChangeAnimator == null) { - mQsContainer.setHeightOverride(mQsContainer.getDesiredHeight()); + if (mQsSizeChangeAnimator == null && mQs != null) { + mQs.setHeightOverride(mQs.getDesiredHeight()); } updateMaxHeadsUpTranslation(); } @@ -357,7 +349,7 @@ public class NotificationPanelView extends PanelView implements requestScrollerTopPaddingUpdate(false /* animate */); requestPanelHeightUpdate(); int height = (int) mQsSizeChangeAnimator.getAnimatedValue(); - mQsContainer.setHeightOverride(height); + mQs.setHeightOverride(height); } }); mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() { @@ -377,7 +369,7 @@ public class NotificationPanelView extends PanelView implements boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending(); int stackScrollerPadding; if (mStatusBarState != StatusBarState.KEYGUARD) { - stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight; + stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight; mTopPaddingAdjustment = 0; } else { mClockPositionAlgorithm.setup( @@ -490,7 +482,8 @@ public class NotificationPanelView extends PanelView implements public void setQsExpansionEnabled(boolean qsExpansionEnabled) { mQsExpansionEnabled = qsExpansionEnabled; - mQsContainer.setHeaderClickable(qsExpansionEnabled); + if (mQs == null) return; + mQs.setHeaderClickable(qsExpansionEnabled); } @Override @@ -571,7 +564,7 @@ public class NotificationPanelView extends PanelView implements @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (mBlockTouches || mQsContainer.isCustomizing()) { + if (mBlockTouches || mQs.isCustomizing()) { return false; } initDownStates(event); @@ -731,7 +724,7 @@ public class NotificationPanelView extends PanelView implements @Override public boolean onTouchEvent(MotionEvent event) { - if (mBlockTouches || mQsContainer.isCustomizing()) { + if (mBlockTouches || (mQs != null && mQs.isCustomizing())) { return false; } initDownStates(event); @@ -804,10 +797,10 @@ public class NotificationPanelView extends PanelView implements } private boolean isInQsArea(float x, float y) { - return (x >= mQsAutoReinflateContainer.getX() - && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()) + return (x >= mQsFrame.getX() + && x <= mQsFrame.getX() + mQsFrame.getWidth()) && (y <= mNotificationStackScroller.getBottomMostNotificationBottom() - || y <= mQsContainer.getY() + mQsContainer.getHeight()); + || y <= mQs.getView().getY() + mQs.getView().getHeight()); } private boolean isOpenQsEvent(MotionEvent event) { @@ -962,7 +955,8 @@ public class NotificationPanelView extends PanelView implements private void setOverScrolling(boolean overscrolling) { mStackScrollerOverscrolling = overscrolling; - mQsContainer.setOverscrolling(overscrolling); + if (mQs == null) return; + mQs.setOverscrolling(overscrolling); } private void onQsExpansionStarted() { @@ -1000,24 +994,28 @@ public class NotificationPanelView extends PanelView implements mStatusBarState = statusBarState; mKeyguardShowing = keyguardShowing; - mQsContainer.setKeyguardShowing(mKeyguardShowing); + if (mQs != null) { + mQs.setKeyguardShowing(mKeyguardShowing); + } if (oldState == StatusBarState.KEYGUARD && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) { animateKeyguardStatusBarOut(); long delay = mStatusBarState == StatusBarState.SHADE_LOCKED ? 0 : mStatusBar.calculateGoingToFullShadeDelay(); - mQsContainer.animateHeaderSlidingIn(delay); + mQs.animateHeaderSlidingIn(delay); } else if (oldState == StatusBarState.SHADE_LOCKED && statusBarState == StatusBarState.KEYGUARD) { animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD); - mQsContainer.animateHeaderSlidingOut(); + mQs.animateHeaderSlidingOut(); } else { mKeyguardStatusBar.setAlpha(1f); mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); if (keyguardShowing && oldState != mStatusBarState) { mKeyguardBottomArea.onKeyguardShowingChanged(); - mQsContainer.hideImmediately(); + if (mQs != null) { + mQs.hideImmediately(); + } } } if (keyguardShowing) { @@ -1163,7 +1161,6 @@ public class NotificationPanelView extends PanelView implements } private void updateQsState() { - mQsContainer.setExpanded(mQsExpanded); mNotificationStackScroller.setQsExpanded(mQsExpanded); mNotificationStackScroller.setScrollingEnabled( mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded @@ -1176,6 +1173,8 @@ public class NotificationPanelView extends PanelView implements if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) { mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); } + if (mQs == null) return; + mQs.setExpanded(mQsExpanded); } private void setQsExpansion(float height) { @@ -1222,11 +1221,12 @@ public class NotificationPanelView extends PanelView implements } protected void updateQsExpansion() { - mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation()); + if (mQs == null) return; + mQs.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation()); } private String getKeyguardOrLockScreenString() { - if (mQsContainer.isCustomizing()) { + if (mQs != null && mQs.isCustomizing()) { return getContext().getString(R.string.accessibility_desc_quick_settings_edit); } else if (mStatusBarState == StatusBarState.KEYGUARD) { return getContext().getString(R.string.accessibility_desc_lock_screen); @@ -1357,9 +1357,9 @@ public class NotificationPanelView extends PanelView implements if (!mQsExpansionEnabled || mCollapsedOnDown) { return false; } - View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader(); - boolean onHeader = x >= mQsAutoReinflateContainer.getX() - && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth() + View header = mKeyguardShowing ? mKeyguardStatusBar : mQs.getHeader(); + final boolean onHeader = x >= mQsFrame.getX() + && x <= mQsFrame.getX() + mQsFrame.getWidth() && y >= header.getTop() && y <= header.getBottom(); if (mQsExpanded) { return onHeader || (yDiff < 0 && isInQsArea(x, y)); @@ -1621,7 +1621,8 @@ public class NotificationPanelView extends PanelView implements } // Since there are QS tiles in the header now, we need to make sure we start listening // immediately so they can be up to date. - mQsContainer.setHeaderListening(true); + if (mQs == null) return; + mQs.setHeaderListening(true); } @Override @@ -1659,8 +1660,9 @@ public class NotificationPanelView extends PanelView implements } private void setListening(boolean listening) { - mQsContainer.setListening(listening); mKeyguardStatusBar.setListening(listening); + if (mQs == null) return; + mQs.setListening(listening); } @Override @@ -1748,7 +1750,7 @@ public class NotificationPanelView extends PanelView implements } public void onQsHeightChanged() { - mQsMaxExpansionHeight = mQsContainer.getDesiredHeight(); + mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0; if (mQsExpanded && mQsFullyExpanded) { mQsExpansionHeight = mQsMaxExpansionHeight; requestScrollerTopPaddingUpdate(false /* animate */); @@ -2018,11 +2020,11 @@ public class NotificationPanelView extends PanelView implements } public boolean isQsDetailShowing() { - return mQsContainer.isShowingDetail(); + return mQs.isShowingDetail(); } public void closeQsDetail() { - mQsContainer.closeDetail(); + mQs.closeDetail(); } @Override @@ -2110,7 +2112,7 @@ public class NotificationPanelView extends PanelView implements private final Runnable mUpdateHeader = new Runnable() { @Override public void run() { - mQsContainer.getHeader().updateEverything(); + mQs.getHeader().updateEverything(); } }; @@ -2257,7 +2259,7 @@ public class NotificationPanelView extends PanelView implements protected void setVerticalPanelTranslation(float translation) { mNotificationStackScroller.setTranslationX(translation); - mQsAutoReinflateContainer.setTranslationX(translation); + mQsFrame.setTranslationX(translation); } protected void updateExpandedHeight(float expandedHeight) { @@ -2355,4 +2357,38 @@ public class NotificationPanelView extends PanelView implements public void setGroupManager(NotificationGroupManager groupManager) { mGroupManager = groupManager; } + + private final FragmentListener mFragmentListener = new FragmentListener() { + @Override + public void onFragmentViewCreated(String tag, Fragment fragment) { + mQs = (QS) fragment; + mQs.setPanelView(NotificationPanelView.this); + mQs.getHeader().getExpandView().setOnClickListener(NotificationPanelView.this); + mQs.setHeaderClickable(mQsExpansionEnabled); + mQs.setKeyguardShowing(mKeyguardShowing); + mQs.setOverscrolling(mStackScrollerOverscrolling); + + // recompute internal state when qspanel height changes + mQs.getView().addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + final int height = bottom - top; + final int oldHeight = oldBottom - oldTop; + if (height != oldHeight) { + onQsHeightChanged(); + } + }); + mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView()); + updateQsExpansion(); + } + + @Override + public void onFragmentViewDestroyed(String tag, Fragment fragment) { + // Manual handling of fragment lifecycle is only required because this bridges + // non-fragment and fragment code. Once we are using a fragment for the notification + // panel, mQs will not need to be null cause it will be tied to the same lifecycle. + if (fragment == mQs) { + mQs = null; + } + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java index 8b1fcd6b104f..c85584e97386 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import android.app.Fragment; import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; @@ -25,18 +26,17 @@ import android.view.ViewStub; import android.view.WindowInsets; import android.widget.FrameLayout; -import com.android.systemui.AutoReinflateContainer; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer; +import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.plugins.qs.QS; /** * The container with notification stack scroller and quick settings inside. */ public class NotificationsQuickSettingsContainer extends FrameLayout - implements ViewStub.OnInflateListener, AutoReinflateContainer.InflateListener { + implements ViewStub.OnInflateListener, FragmentHostManager.FragmentListener { - - private AutoReinflateContainer mQsContainer; + private FrameLayout mQsFrame; private View mUserSwitcher; private View mStackScroller; private View mKeyguardStatusBar; @@ -54,8 +54,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout @Override protected void onFinishInflate() { super.onFinishInflate(); - mQsContainer = (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container); - mQsContainer.addInflateListener(this); + mQsFrame = (FrameLayout) findViewById(R.id.qs_frame); mStackScroller = findViewById(R.id.notification_stack_scroller); mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin; mKeyguardStatusBar = findViewById(R.id.keyguard_header); @@ -65,9 +64,21 @@ public class NotificationsQuickSettingsContainer extends FrameLayout } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + FragmentHostManager.get(this).addTagListener(QS.TAG, this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + FragmentHostManager.get(this).removeTagListener(QS.TAG, this); + } + + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - reloadWidth(mQsContainer); + reloadWidth(mQsFrame); reloadWidth(mStackScroller); } @@ -91,11 +102,11 @@ public class NotificationsQuickSettingsContainer extends FrameLayout boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE; final boolean qsBottom = mQsExpanded && !mCustomizerAnimating; - View stackQsTop = qsBottom ? mStackScroller : mQsContainer; - View stackQsBottom = !qsBottom ? mStackScroller : mQsContainer; + View stackQsTop = qsBottom ? mStackScroller : mQsFrame; + View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame; // Invert the order of the scroll view and user switcher such that the notifications receive // touches first but the panel gets drawn above. - if (child == mQsContainer) { + if (child == mQsFrame) { return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher : statusBarVisible ? mKeyguardStatusBar : userSwitcherVisible ? mUserSwitcher @@ -129,8 +140,8 @@ public class NotificationsQuickSettingsContainer extends FrameLayout } @Override - public void onInflated(View v) { - QSContainer container = (QSContainer) v; + public void onFragmentViewCreated(String tag, Fragment fragment) { + QS container = (QS) fragment; container.setContainer(this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index c33d91a9a29d..6f13ba50b22f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -34,7 +34,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.app.IActivityManager; import android.app.Notification; @@ -90,7 +89,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; -import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.telecom.TelecomManager; @@ -118,7 +116,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.StatusBarIcon; import com.android.keyguard.KeyguardHostView.OnDismissAction; @@ -126,8 +124,6 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.AutoReinflateContainer; -import com.android.systemui.AutoReinflateContainer.InflateListener; import com.android.systemui.BatteryMeterView; import com.android.systemui.DemoMode; import com.android.systemui.EventLogConstants; @@ -141,11 +137,13 @@ import com.android.systemui.classifier.FalsingLog; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; +import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.fragments.PluginFragmentListener; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.plugins.qs.QSContainer.ActivityStarter; -import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader; -import com.android.systemui.plugins.qs.QSContainer; -import com.android.systemui.qs.QSContainerImpl; +import com.android.systemui.plugins.qs.QS; +import com.android.systemui.plugins.qs.QS.ActivityStarter; +import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader; +import com.android.systemui.qs.QSFragment; import com.android.systemui.qs.QSPanel; import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.recents.events.EventBus; @@ -561,6 +559,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private int mLastCameraLaunchSource; private PowerManager.WakeLock mGestureWakeLock; private Vibrator mVibrator; + private long[] mCameraLaunchGestureVibePattern; // Fingerprint (as computed by getLoggingFingerprint() of the last logged state. private int mLastLoggedStateFingerprint; @@ -874,7 +873,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mLocationController = new LocationControllerImpl(mContext, mHandlerThread.getLooper()); // will post a notification mBatteryController = createBatteryController(); - mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { + mBatteryController.addCallback(new BatteryStateChangeCallback() { @Override public void onPowerSaveChanged(boolean isPowerSave) { mHandler.post(mCheckBarModes); @@ -922,9 +921,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } // Set up the quick settings tile panel - AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById( - R.id.qs_auto_reinflate_container); + View container = mStatusBarWindow.findViewById(R.id.qs_frame); if (container != null) { + FragmentHostManager fragmentHostManager = FragmentHostManager.get(container); + new PluginFragmentListener(container, QS.TAG, R.id.qs_frame, QSFragment.class, QS.class) + .startListening(QS.ACTION, QS.VERSION); final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, mBluetoothController, mLocationController, mRotationLockController, mNetworkController, mZenModeController, mHotspotController, @@ -933,21 +934,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mSecurityController, mBatteryController, mIconController, mNextAlarmController); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); - container.addInflateListener(new InflateListener() { - @Override - public void onInflated(View v) { - QSContainer qsContainer = (QSContainer) v.findViewById( - R.id.quick_settings_container); - if (qsContainer instanceof QSContainerImpl) { - ((QSContainerImpl) qsContainer).setHost(qsh); - mQSPanel = ((QSContainerImpl) qsContainer).getQsPanel(); - mQSPanel.setBrightnessMirror(mBrightnessMirrorController); - mKeyguardStatusBar.setQSPanel(mQSPanel); - } - mHeader = qsContainer.getHeader(); - initSignalCluster(mHeader); - mHeader.setActivityStarter(PhoneStatusBar.this); + fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> { + QS qs = (QS) f; + if (qs instanceof QSFragment) { + ((QSFragment) qs).setHost(qsh); + mQSPanel = ((QSFragment) qs).getQsPanel(); + mQSPanel.setBrightnessMirror(mBrightnessMirrorController); + mKeyguardStatusBar.setQSPanel(mQSPanel); } + mHeader = qs.getHeader(); + initSignalCluster(mHeader); + mHeader.setActivityStarter(PhoneStatusBar.this); }); } @@ -996,6 +993,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GestureWakeLock"); mVibrator = mContext.getSystemService(Vibrator.class); + int[] pattern = mContext.getResources().getIntArray( + R.array.config_cameraLaunchGestureVibePattern); + mCameraLaunchGestureVibePattern = new long[pattern.length]; + for (int i = 0; i < pattern.length; i++) { + mCameraLaunchGestureVibePattern[i] = pattern[i]; + } // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -1030,7 +1033,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (emergencyViewStub != null) { ((ViewStub) emergencyViewStub).inflate(); } - mNetworkController.addSignalCallback(new NetworkController.SignalCallback() { + mNetworkController.addCallback(new NetworkController.SignalCallback() { @Override public void setIsAirplaneMode(NetworkController.IconState icon) { recomputeDisableFlags(true /* animate */); @@ -1649,9 +1652,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(), - sbn.getOpPkg(), + sbn.getOpPkg(), sbn.getNotificationChannel(), sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), - 0, newNotification, sbn.getUser(), sbn.getPostTime()); + newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); updateNotification(newSbn, null); mKeysKeptForRemoteInput.add(entry.key); @@ -3512,7 +3515,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); } try { - result = ActivityManagerNative.getDefault().startActivityAsUser( + result = ActivityManager.getService().startActivityAsUser( null, mContext.getBasePackageName(), intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), @@ -3552,8 +3555,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, AsyncTask.execute(runnable); } if (dismissShade) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, - true /* delayed*/); + if (mExpandedVisible) { + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */, + true /* delayed*/); + } else { + + // Do it after DismissAction has been processed to conserve the needed ordering. + mHandler.post(this::runPostCollapseRunnables); + } } return deferred; }, cancelAction, afterKeyguardGone); @@ -3631,12 +3640,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone); } - public void dismissKeyguard() { - mStatusBarKeyguardViewManager.dismiss(); - } - private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) { + afterKeyguardGone |= mStatusBarKeyguardViewManager.isShowing() + && mStatusBarKeyguardViewManager.isOccluded(); if (mStatusBarKeyguardViewManager.isShowing()) { mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, afterKeyguardGone); @@ -3974,9 +3981,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterQs = (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); - mNetworkController.removeSignalCallback(signalCluster); - mNetworkController.removeSignalCallback(signalClusterKeyguard); - mNetworkController.removeSignalCallback(signalClusterQs); + mNetworkController.removeCallback(signalCluster); + mNetworkController.removeCallback(signalClusterKeyguard); + mNetworkController.removeCallback(signalClusterQs); if (mQSPanel != null && mQSPanel.getHost() != null) { mQSPanel.getHost().destroy(); } @@ -4249,7 +4256,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE); } - } else { + } else if (!mNotificationPanel.isCollapsing()) { instantCollapseNotificationPanel(); } updateKeyguardState(staying, false /* fromShadeLocked */); @@ -4876,7 +4883,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void vibrateForCameraGesture() { // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep. - mVibrator.vibrate(new long[]{0, 400}, -1 /* repeat */); + mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */); } public void onScreenTurnedOn() { @@ -4889,7 +4896,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, */ private boolean handleLongPressBack() { try { - IActivityManager activityManager = ActivityManagerNative.getDefault(); + IActivityManager activityManager = ActivityManager.getService(); if (activityManager.isInLockTaskMode()) { activityManager.stopSystemLockTaskMode(); @@ -5160,5 +5167,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return mNotificationLightOn; } + @Override + public void startPendingIntentDismissingKeyguard(PendingIntent intent) { + PhoneStatusBar.this.startPendingIntentDismissingKeyguard(intent); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 7187ec23f59e..9ee1e8f03137 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AlarmManager.AlarmClockInfo; import android.app.SynchronousUserSwitchObserver; @@ -47,7 +46,6 @@ import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.NextAlarmController; -import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -110,7 +108,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro mCast = cast; mHotspot = hotspot; mBluetooth = bluetooth; - mBluetooth.addStateChangedCallback(this); + mBluetooth.addCallback(this); mNextAlarm = nextAlarm; mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mUserInfoController = userInfoController; @@ -131,7 +129,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset); mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver); - mRotationLockController.addRotationLockControllerCallback(this); + mRotationLockController.addCallback(this); // listen for broadcasts IntentFilter filter = new IntentFilter(); @@ -147,7 +145,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro // listen for user / profile change. try { - ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener, TAG); + ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG); } catch (RemoteException e) { // Ignore } @@ -162,7 +160,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro // Alarm clock mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null); mIconController.setIconVisibility(mSlotAlarmClock, false); - mNextAlarm.addStateChangedCallback(mNextAlarmCallback); + mNextAlarm.addCallback(mNextAlarmCallback); // zen mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null); @@ -193,7 +191,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver, context.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); - mDataSaver.addListener(this); + mDataSaver.addCallback(this); } public void setStatusBarKeyguardViewManager( @@ -381,7 +379,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro UserInfo user = null; if (userId == UserHandle.USER_CURRENT) { try { - user = ActivityManagerNative.getDefault().getCurrentUser(); + user = ActivityManager.getService().getCurrentUser(); } catch (RemoteException e) { // Ignore } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index da698d8a95d4..fc15477e3702 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -113,6 +113,7 @@ public class QSTileHost implements QSTile.Host, Tunable { private final AutoTileManager mAutoTiles; private final ManagedProfileController mProfileController; private final NextAlarmController mNextAlarmController; + private final HandlerThread mHandlerThread; private View mHeader; private int mCurrentUser; @@ -144,10 +145,10 @@ public class QSTileHost implements QSTile.Host, Tunable { mNextAlarmController = nextAlarmController; mProfileController = new ManagedProfileController(this); - final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(), + mHandlerThread = new HandlerThread(QSTileHost.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND); - ht.start(); - mLooper = ht.getLooper(); + mHandlerThread.start(); + mLooper = mHandlerThread.getLooper(); mServices = new TileServices(this, mLooper); @@ -169,8 +170,11 @@ public class QSTileHost implements QSTile.Host, Tunable { } public void destroy() { + mHandlerThread.quitSafely(); + mTiles.values().forEach(tile -> tile.destroy()); mAutoTiles.destroy(); TunerService.get(mContext).removeTunable(this); + mServices.destroy(); } @Override @@ -321,12 +325,11 @@ public class QSTileHost implements QSTile.Host, Tunable { final List<String> tileSpecs = loadTileSpecs(mContext, newValue); int currentUser = ActivityManager.getCurrentUser(); if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return; - for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) { - if (!tileSpecs.contains(tile.getKey())) { - if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey()); - tile.getValue().destroy(); - } - } + mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach( + tile -> { + if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey()); + tile.getValue().destroy(); + }); final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>(); for (String tileSpec : tileSpecs) { QSTile<?> tile = mTiles.get(tileSpec); @@ -342,9 +345,13 @@ public class QSTileHost implements QSTile.Host, Tunable { if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec); try { tile = createTile(tileSpec); - if (tile != null && tile.isAvailable()) { - tile.setTileSpec(tileSpec); - newTiles.put(tileSpec, tile); + if (tile != null) { + if (tile.isAvailable()) { + tile.setTileSpec(tileSpec); + newTiles.put(tileSpec, tile); + } else { + tile.destroy(); + } } } catch (Throwable t) { Log.w(TAG, "Error creating tile for spec: " + tileSpec, t); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index a8b0122a9470..28aed878b506 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -33,14 +33,14 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; -import com.android.systemui.plugins.qs.QSContainer.ActivityStarter; -import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader; +import com.android.systemui.plugins.qs.QS.ActivityStarter; +import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader; import com.android.systemui.qs.QSPanel; -import com.android.systemui.plugins.qs.QSContainer.Callback; +import com.android.systemui.plugins.qs.QS.Callback; import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.TouchAnimator; import com.android.systemui.qs.TouchAnimator.Builder; @@ -238,7 +238,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements @Override protected void onDetachedFromWindow() { setListening(false); - mHost.getUserInfoController().remListener(this); + mHost.getUserInfoController().removeCallback(this); mHost.getNetworkController().removeEmergencyListener(this); super.onDetachedFromWindow(); } @@ -290,9 +290,9 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements private void updateListeners() { if (mListening) { - mNextAlarmController.addStateChangedCallback(this); + mNextAlarmController.addCallback(this); } else { - mNextAlarmController.removeStateChangedCallback(this); + mNextAlarmController.removeCallback(this); } } @@ -368,7 +368,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements } public void setUserInfoController(UserInfoController userInfoController) { - userInfoController.addListener(this); + userInfoController.addCallback(this); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f5c5e56359a7..69decd72c03a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -155,8 +155,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (!afterKeyguardGone) { mBouncer.showWithDismissAction(r, cancelAction); } else { - mBouncer.show(false /* resetSecuritySelection */); mAfterKeyguardGoneAction = r; + mBouncer.show(false /* resetSecuritySelection */); } } updateStates(); @@ -235,10 +235,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mDeviceWillWakeUp = !mDeviceInteractive; } - public void verifyUnlock() { - dismiss(); - } - public void setNeedsInput(boolean needsInput) { mStatusBarWindowManager.setKeyguardNeedsInput(needsInput); } @@ -333,6 +329,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } }); } else { + executeAfterKeyguardGoneAction(); if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) { mFingerprintUnlockController.startKeyguardFadingAway(); mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240); @@ -372,7 +369,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBarWindowManager.setKeyguardShowing(false); mBouncer.hide(true /* destroyView */); mViewMediatorCallback.keyguardGone(); - executeAfterKeyguardGoneAction(); updateStates(); } } @@ -423,6 +419,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb /** * Dismisses the keyguard by going to the next screen or making it gone. */ + public void dismissAndCollapse() { + mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true); + } + public void dismiss() { showBouncer(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index 4a2d5dcda967..995f4ddf35d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.phone; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Context; import android.content.pm.ActivityInfo; @@ -64,7 +64,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback { public StatusBarWindowManager(Context context) { mContext = context; mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - mActivityManager = ActivityManagerNative.getDefault(); + mActivityManager = ActivityManager.getService(); mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); mScreenBrightnessDoze = mContext.getResources().getInteger( com.android.internal.R.integer.config_screenBrightnessDoze) / 255f; 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/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 559436b10eed..19dcf03d470c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -17,11 +17,13 @@ package com.android.systemui.statusbar.policy; import com.android.systemui.DemoMode; +import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import java.io.FileDescriptor; import java.io.PrintWriter; -public interface BatteryController extends DemoMode { +public interface BatteryController extends DemoMode, + CallbackController<BatteryStateChangeCallback> { /** * Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}. */ @@ -37,9 +39,6 @@ public interface BatteryController extends DemoMode { */ boolean isPowerSave(); - void addStateChangedCallback(BatteryStateChangeCallback cb); - void removeStateChangedCallback(BatteryStateChangeCallback cb); - /** * A listener that will be notified whenever a change in battery level or power save mode * has occurred. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 6726c9200a58..fc86ac332c82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -89,7 +89,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } @Override - public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { + public void addCallback(BatteryController.BatteryStateChangeCallback cb) { synchronized (mChangeCallbacks) { mChangeCallbacks.add(cb); } @@ -99,7 +99,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } @Override - public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { + public void removeCallback(BatteryController.BatteryStateChangeCallback cb) { synchronized (mChangeCallbacks) { mChangeCallbacks.remove(cb); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java index 08675c4f027c..4c1c378b4f45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java @@ -17,13 +17,11 @@ package com.android.systemui.statusbar.policy; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.systemui.statusbar.policy.BluetoothController.Callback; import java.util.Collection; -public interface BluetoothController { - void addStateChangedCallback(Callback callback); - void removeStateChangedCallback(Callback callback); - +public interface BluetoothController extends CallbackController<Callback> { boolean isBluetoothSupported(); boolean isBluetoothEnabled(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java index 4f880b446f2c..15c4afeba581 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java @@ -105,13 +105,13 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa } @Override - public void addStateChangedCallback(Callback cb) { + public void addCallback(Callback cb) { mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget(); mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED); } @Override - public void removeStateChangedCallback(Callback cb) { + public void removeCallback(Callback cb) { mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java new file mode 100644 index 000000000000..9042ca6d15ca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +public interface CallbackController<T> { + void addCallback(T listener); + void removeCallback(T listener); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java index 7713e576c8db..6988af7d0ed3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java @@ -16,11 +16,11 @@ package com.android.systemui.statusbar.policy; +import com.android.systemui.statusbar.policy.CastController.Callback; + import java.util.Set; -public interface CastController { - void addCallback(Callback callback); - void removeCallback(Callback callback); +public interface CastController extends CallbackController<Callback> { void setDiscovering(boolean request); void setCurrentUserId(int currentUserId); Set<CastDevice> getCastDevices(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java index 0fc71d30b514..e5f1e68f8184 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java @@ -21,9 +21,11 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import com.android.systemui.statusbar.policy.DataSaverController.Listener; + import java.util.ArrayList; -public class DataSaverController { +public class DataSaverController implements CallbackController<Listener> { private final Handler mHandler = new Handler(Looper.getMainLooper()); private final ArrayList<Listener> mListeners = new ArrayList<>(); @@ -41,7 +43,7 @@ public class DataSaverController { } } - public void addListener(Listener listener) { + public void addCallback(Listener listener) { synchronized (mListeners) { mListeners.add(listener); if (mListeners.size() == 1) { @@ -51,7 +53,7 @@ public class DataSaverController { listener.onDataSaverChanged(isDataSaverEnabled()); } - public void remListener(Listener listener) { + public void removeCallback(Listener listener) { synchronized (mListeners) { mListeners.remove(listener); if (mListeners.size() == 0) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java index 4e9fc76f7059..0f77b03b1711 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java @@ -27,6 +27,8 @@ import android.os.Process; import android.text.TextUtils; import android.util.Log; +import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -35,7 +37,7 @@ import java.util.ArrayList; /** * Manages the flashlight. */ -public class FlashlightController { +public class FlashlightController implements CallbackController<FlashlightListener> { private static final String TAG = "FlashlightController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -112,7 +114,7 @@ public class FlashlightController { return mTorchAvailable; } - public void addListener(FlashlightListener l) { + public void addCallback(FlashlightListener l) { synchronized (mListeners) { if (mCameraId == null) { tryInitCamera(); @@ -122,7 +124,7 @@ public class FlashlightController { } } - public void removeListener(FlashlightListener l) { + public void removeCallback(FlashlightListener l) { synchronized (mListeners) { cleanUpListenersLocked(l); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java index 4622ea473405..daf9d6b2e88d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java @@ -16,9 +16,9 @@ package com.android.systemui.statusbar.policy; -public interface HotspotController { - void addCallback(Callback callback); - void removeCallback(Callback callback); +import com.android.systemui.statusbar.policy.HotspotController.Callback; + +public interface HotspotController extends CallbackController<Callback> { boolean isHotspotEnabled(); void setHotspotEnabled(boolean enabled); boolean isHotspotSupported(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index 44816f92b222..fafbdd101e5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -24,10 +24,12 @@ import android.view.WindowManagerGlobal; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.settings.CurrentUserTracker; +import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback; import java.util.ArrayList; -public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback { +public class KeyguardMonitor extends KeyguardUpdateMonitorCallback + implements CallbackController<Callback> { private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index 29a8981fd89e..9a5f1b8cbc63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -16,11 +16,11 @@ package com.android.systemui.statusbar.policy; -public interface LocationController { +import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback; + +public interface LocationController extends CallbackController<LocationSettingsChangeCallback> { boolean isLocationEnabled(); boolean setLocationEnabled(boolean enabled); - void addSettingsChangedCallback(LocationSettingsChangeCallback cb); - void removeSettingsChangedCallback(LocationSettingsChangeCallback cb); /** * A callback for change in location settings (the user has enabled/disabled location). diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java index 8d84be485c91..cc61605a5aa6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java @@ -82,12 +82,12 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio /** * Add a callback to listen for changes in location settings. */ - public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) { + public void addCallback(LocationSettingsChangeCallback cb) { mSettingsChangeCallbacks.add(cb); mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED); } - public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) { + public void removeCallback(LocationSettingsChangeCallback cb) { mSettingsChangeCallbacks.remove(cb); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 5f1b8719c9b0..082fe82a2fb9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -21,14 +21,15 @@ import android.content.Intent; import android.telephony.SubscriptionInfo; import com.android.settingslib.net.DataUsageController; import com.android.settingslib.wifi.AccessPoint; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import java.util.List; -public interface NetworkController { +public interface NetworkController extends CallbackController<SignalCallback> { boolean hasMobileDataFeature(); - void addSignalCallback(SignalCallback cb); - void removeSignalCallback(SignalCallback cb); + void addCallback(SignalCallback cb); + void removeCallback(SignalCallback cb); void setWifiEnabled(boolean enabled); void onUserSwitched(int newUserId); AccessPointController getAccessPointController(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 37e6a2ab8ead..1a9756f78e36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -322,7 +322,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mCallbackHandler.setEmergencyCallsOnly(mIsEmergency); } - public void addSignalCallback(SignalCallback cb) { + public void addCallback(SignalCallback cb) { cb.setSubs(mCurrentSubscriptions); cb.setIsAirplaneMode(new IconState(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); @@ -336,7 +336,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } @Override - public void removeSignalCallback(SignalCallback cb) { + public void removeCallback(SignalCallback cb) { mCallbackHandler.setListening(cb, false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java index 787acc53a44b..28935bff9ec5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java @@ -23,11 +23,14 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.UserHandle; +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -public class NextAlarmController extends BroadcastReceiver { +public class NextAlarmController extends BroadcastReceiver + implements CallbackController<NextAlarmChangeCallback> { private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>(); @@ -48,12 +51,12 @@ public class NextAlarmController extends BroadcastReceiver { pw.print(" mNextAlarm="); pw.println(mNextAlarm); } - public void addStateChangedCallback(NextAlarmChangeCallback cb) { + public void addCallback(NextAlarmChangeCallback cb) { mChangeCallbacks.add(cb); cb.onNextAlarmChanged(mNextAlarm); } - public void removeStateChangedCallback(NextAlarmChangeCallback cb) { + public void removeCallback(NextAlarmChangeCallback cb) { mChangeCallbacks.remove(cb); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 7b1f7071b5c7..44ec2831dd9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -50,7 +50,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.ExpandableView; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java index 93c46918effe..722874b07c97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java @@ -16,13 +16,14 @@ package com.android.systemui.statusbar.policy; -public interface RotationLockController extends Listenable { +import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; + +public interface RotationLockController extends Listenable, + CallbackController<RotationLockControllerCallback> { int getRotationLockOrientation(); boolean isRotationLockAffordanceVisible(); boolean isRotationLocked(); void setRotationLocked(boolean locked); - void addRotationLockControllerCallback(RotationLockControllerCallback callback); - void removeRotationLockControllerCallback(RotationLockControllerCallback callback); public interface RotationLockControllerCallback { void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java index c3bcd946c70c..4f964964cd68 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java @@ -42,12 +42,12 @@ public final class RotationLockControllerImpl implements RotationLockController setListening(true); } - public void addRotationLockControllerCallback(RotationLockControllerCallback callback) { + public void addCallback(RotationLockControllerCallback callback) { mCallbacks.add(callback); notifyChanged(callback); } - public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) { + public void removeCallback(RotationLockControllerCallback callback) { mCallbacks.remove(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java index 014afae7bf5a..43ced4898365 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java @@ -15,7 +15,9 @@ */ package com.android.systemui.statusbar.policy; -public interface SecurityController { +import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback; + +public interface SecurityController extends CallbackController<SecurityControllerCallback> { /** Whether the device has device owner, even if not on this user. */ boolean isDeviceManaged(); boolean hasProfileOwner(); @@ -29,9 +31,6 @@ public interface SecurityController { String getProfileVpnName(); void onUserSwitched(int newUserId); - void addCallback(SecurityControllerCallback callback); - void removeCallback(SecurityControllerCallback callback); - public interface SecurityControllerCallback { void onStateChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java index 4a6e215c493c..c09747b73f95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -38,10 +37,11 @@ import android.util.Log; import com.android.internal.util.UserIcons; import com.android.settingslib.drawable.UserIconDrawable; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener; import java.util.ArrayList; -public final class UserInfoController { +public class UserInfoController implements CallbackController<OnUserInfoChangedListener> { private static final String TAG = "UserInfoController"; @@ -67,12 +67,12 @@ public final class UserInfoController { null, null); } - public void addListener(OnUserInfoChangedListener callback) { + public void addCallback(OnUserInfoChangedListener callback) { mCallbacks.add(callback); callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); } - public void remListener(OnUserInfoChangedListener callback) { + public void removeCallback(OnUserInfoChangedListener callback) { mCallbacks.remove(callback); } @@ -93,7 +93,7 @@ public final class UserInfoController { if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || Intent.ACTION_USER_INFO_CHANGED.equals(action)) { try { - final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id; + final int currentUser = ActivityManager.getService().getCurrentUser().id; final int changedUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); if (changedUser == currentUser) { @@ -118,7 +118,7 @@ public final class UserInfoController { Context currentUserContext; UserInfo userInfo; try { - userInfo = ActivityManagerNative.getDefault().getCurrentUser(); + userInfo = ActivityManager.getService().getCurrentUser(); currentUserContext = mContext.createPackageContextAsUser("android", 0, new UserHandle(userInfo.id)); } catch (PackageManager.NameNotFoundException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 30d1c54b4096..bb4b91ef3860 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.policy; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.Dialog; import android.app.Notification; import android.app.NotificationManager; @@ -48,16 +47,17 @@ import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.UserIcons; import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.SystemUISecondaryUserService; -import com.android.systemui.plugins.qs.QSContainer.DetailAdapter; +import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.tiles.UserDetailView; -import com.android.systemui.plugins.qs.QSContainer.ActivityStarter; +import com.android.systemui.plugins.qs.QS.ActivityStarter; import com.android.systemui.statusbar.phone.SystemUIDialog; import java.io.FileDescriptor; @@ -411,7 +411,7 @@ public class UserSwitcherController { protected void switchToUserId(int id) { try { pauseRefreshUsers(); - ActivityManagerNative.getDefault().switchUser(id); + ActivityManager.getService().switchUser(id); } catch (RemoteException e) { Log.e(TAG, "Couldn't switch user.", e); } @@ -640,28 +640,43 @@ public class UserSwitcherController { refreshUsers(UserHandle.USER_ALL); } + @VisibleForTesting + public void addAdapter(WeakReference<BaseUserAdapter> adapter) { + mAdapters.add(adapter); + } + + @VisibleForTesting + public KeyguardMonitor getKeyguardMonitor() { + return mKeyguardMonitor; + } + + @VisibleForTesting + public ArrayList<UserRecord> getUsers() { + return mUsers; + } + public static abstract class BaseUserAdapter extends BaseAdapter { final UserSwitcherController mController; protected BaseUserAdapter(UserSwitcherController controller) { mController = controller; - controller.mAdapters.add(new WeakReference<>(this)); + controller.addAdapter(new WeakReference<>(this)); } @Override public int getCount() { - boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing() - && mController.mKeyguardMonitor.isSecure() - && !mController.mKeyguardMonitor.canSkipBouncer(); + boolean secureKeyguardShowing = mController.getKeyguardMonitor().isShowing() + && mController.getKeyguardMonitor().isSecure() + && !mController.getKeyguardMonitor().canSkipBouncer(); if (!secureKeyguardShowing) { - return mController.mUsers.size(); + return mController.getUsers().size(); } // The lock screen is secure and showing. Filter out restricted records. - final int N = mController.mUsers.size(); + final int N = mController.getUsers().size(); int count = 0; for (int i = 0; i < N; i++) { - if (mController.mUsers.get(i).isRestricted) { + if (mController.getUsers().get(i).isRestricted) { break; } else { count++; @@ -672,7 +687,7 @@ public class UserSwitcherController { @Override public UserRecord getItem(int position) { - return mController.mUsers.get(position); + return mController.getUsers().get(position); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index 0e91b0b4a9b4..bcdb62dcbd78 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -22,9 +22,9 @@ import android.service.notification.Condition; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ZenRule; -public interface ZenModeController { - void addCallback(Callback callback); - void removeCallback(Callback callback); +import com.android.systemui.statusbar.policy.ZenModeController.Callback; + +public interface ZenModeController extends CallbackController<Callback> { void setZen(int zen, Uri conditionId, String reason); int getZen(); ZenRule getManualRule(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index da58d9e98a6b..72a0e5929a17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -57,7 +57,7 @@ import android.widget.OverScroller; import android.widget.ScrollView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.ExpandHelper; import com.android.systemui.Interpolators; import com.android.systemui.R; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java index 6e08139267ef..9998283e1a05 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java @@ -21,7 +21,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.AttributeSet; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.statusbar.phone.StatusBarIconController; import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java index 0a3197c039cf..0a962f1f2519 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java @@ -31,7 +31,7 @@ import android.support.v7.preference.PreferenceScreen; import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.DemoMode; import com.android.systemui.R; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java index 14fccf21af43..8740a3c2f45a 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java @@ -16,7 +16,7 @@ package com.android.systemui.tuner; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import android.annotation.Nullable; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java index f2f0382060c7..dea2f5060c3a 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java @@ -24,7 +24,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService.Tunable; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java new file mode 100644 index 000000000000..a068172a2dd3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.tuner; + +import android.app.AlertDialog; +import android.app.UiModeManager; +import android.content.Context; +import android.os.SystemProperties; +import android.support.v7.preference.ListPreference; +import android.text.TextUtils; +import android.util.AttributeSet; + +import com.android.systemui.R; + +import libcore.util.Objects; + +import com.google.android.collect.Lists; + +import java.io.File; +import java.util.ArrayList; + +public class ThemePreference extends ListPreference { + + public ThemePreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void onAttached() { + super.onAttached(); + String def = SystemProperties.get("ro.boot.vendor.overlay.theme"); + if (TextUtils.isEmpty(def)) { + def = getContext().getString(R.string.default_theme); + } + String[] fileList = new File("/vendor/overlay").list(); + ArrayList<String> options = fileList != null + ? Lists.newArrayList(fileList) : new ArrayList<>(); + if (!options.contains(def)) { + options.add(0, def); + } + String[] list = options.toArray(new String[options.size()]); + setVisible(options.size() > 1); + setEntries(list); + setEntryValues(list); + updateValue(); + } + + private void updateValue() { + setValue(getContext().getSystemService(UiModeManager.class).getTheme()); + } + + @Override + protected void notifyChanged() { + super.notifyChanged(); + if (!Objects.equal(getValue(), + getContext().getSystemService(UiModeManager.class).getTheme())) { + new AlertDialog.Builder(getContext()) + .setTitle(R.string.change_theme_reboot) + .setPositiveButton(com.android.internal.R.string.global_action_restart, (d, i) + -> getContext().getSystemService(UiModeManager.class) + .setTheme(getValue())) + .setNegativeButton(android.R.string.cancel, (d, i) -> updateValue()) + .show(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index 7f63418de324..f835e7d57ad4 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -27,7 +27,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.plugins.PluginPrefs; @@ -102,7 +102,9 @@ public class TunerFragment extends PreferenceFragment { TunerService.showResetRequest(getContext(), new Runnable() { @Override public void run() { - getActivity().finish(); + if (getActivity() != null) { + getActivity().finish(); + } } }); return true; diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java index 8e0f9b88af3e..ca53bc4f7928 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Events.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java @@ -23,7 +23,7 @@ import android.provider.Settings.Global; import android.util.Log; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.volume.VolumeDialogController.State; import java.util.Arrays; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 8ca277ecdcfd..42b06b2b52c9 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -797,7 +797,7 @@ public class VolumeDialog implements TunerService.Tunable { // update slider final boolean enableSlider = !zenMuted; - final int vlevel = row.ss.muted && (isRingVibrate || !isRingStream && !zenMuted) ? 0 + final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0 : row.ss.level; updateVolumeRowSliderH(row, enableSlider, vlevel); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 22d130941f47..12a00e9fe854 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -52,7 +52,7 @@ import android.widget.RadioGroup; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.statusbar.policy.ZenModeController; @@ -552,8 +552,9 @@ public class ZenModePanel extends LinearLayout { setToMidnight(nextAlarm); if (weekRange.compareTo(nextAlarm) >= 0) { - return ZenModeConfig.toNextAlarmCondition(mContext, now, - nextAlarmMs, ActivityManager.getCurrentUser()); + return ZenModeConfig.toTimeCondition(mContext, nextAlarmMs, + Math.round((nextAlarmMs - now) / (float) MINUTES_MS), + ActivityManager.getCurrentUser(), true); } } return null; diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index b5584f3661be..6e17cf404854 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -25,6 +25,7 @@ <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> + <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java index fccb2a240660..f3be945d5002 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java @@ -16,26 +16,24 @@ package com.android.keyguard; -import com.android.systemui.SysuiTestCase; +import static junit.framework.Assert.assertEquals; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import static org.mockito.Mockito.mock; -import android.content.Context; import android.os.Handler; import android.os.Looper; -import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; -import static junit.framework.Assert.*; -import static org.mockito.Mockito.mock; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class KeyguardMessageAreaTest extends SysuiTestCase { - private Context mContext = InstrumentationRegistry.getTargetContext(); private Handler mHandler = new Handler(Looper.getMainLooper()); private KeyguardMessageArea mMessageArea; diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java index 5cb5e68fe6f8..cb0f7a388d01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java @@ -17,7 +17,7 @@ package com.android.systemui; import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyFloat; import static org.mockito.Mockito.anyString; @@ -28,27 +28,24 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -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; @SmallTest @RunWith(AndroidJUnit4.class) -public class BatteryMeterDrawableTest { +public class BatteryMeterDrawableTest extends SysuiTestCase { - private Context mContext; private Resources mResources; private BatteryMeterDrawable mBatteryMeter; @Before public void setUp() throws Exception { - mContext = InstrumentationRegistry.getTargetContext(); mResources = mContext.getResources(); mBatteryMeter = new BatteryMeterDrawable(mContext, 0); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java new file mode 100644 index 000000000000..f87336c7d151 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui; + +import android.annotation.Nullable; +import android.app.Fragment; +import android.app.FragmentController; +import android.app.FragmentHostCallback; +import android.app.FragmentManagerNonConfig; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Parcelable; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Base class for fragment class tests. Just adding one for any fragment will push it through + * general lifecycle events and ensure no basic leaks are happening. This class also implements + * the host for subclasses, so they can push it into desired states and do any unit testing + * required. + */ +public abstract class FragmentTestCase extends LeakCheckedTest { + + private static final int VIEW_ID = 42; + private final Class<? extends Fragment> mCls; + private HandlerThread mHandlerThread; + private Handler mHandler; + private FrameLayout mView; + protected FragmentController mFragments; + protected Fragment mFragment; + + public FragmentTestCase(Class<? extends Fragment> cls) { + mCls = cls; + } + + @Before + public void setupFragment() throws IllegalAccessException, InstantiationException { + mView = new FrameLayout(mContext); + mView.setId(VIEW_ID); + mHandlerThread = new HandlerThread("FragmentTestThread"); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mFragment = mCls.newInstance(); + postAndWait(() -> { + mFragments = FragmentController.createController(new HostCallbacks()); + mFragments.attachHost(null); + mFragments.getFragmentManager().beginTransaction() + .replace(VIEW_ID, mFragment) + .commit(); + }); + } + + @After + public void tearDown() { + if (mFragments != null) { + // Set mFragments to null to let it know not to destroy. + postAndWait(() -> mFragments.dispatchDestroy()); + } + mHandlerThread.quit(); + } + + @Test + public void testCreateDestroy() { + postAndWait(() -> mFragments.dispatchCreate()); + destroyFragments(); + } + + @Test + public void testStartStop() { + postAndWait(() -> mFragments.dispatchStart()); + postAndWait(() -> mFragments.dispatchStop()); + } + + @Test + public void testResumePause() { + postAndWait(() -> mFragments.dispatchResume()); + postAndWait(() -> mFragments.dispatchPause()); + } + + @Test + public void testRecreate() { + postAndWait(() -> mFragments.dispatchResume()); + postAndWait(() -> { + mFragments.dispatchPause(); + Parcelable p = mFragments.saveAllState(); + mFragments.dispatchDestroy(); + + mFragments = FragmentController.createController(new HostCallbacks()); + mFragments.attachHost(null); + mFragments.restoreAllState(p, (FragmentManagerNonConfig) null); + mFragments.dispatchResume(); + }); + } + + @Test + public void testMultipleResumes() { + postAndWait(() -> mFragments.dispatchResume()); + postAndWait(() -> mFragments.dispatchStop()); + postAndWait(() -> mFragments.dispatchResume()); + } + + protected void destroyFragments() { + postAndWait(() -> mFragments.dispatchDestroy()); + mFragments = null; + } + + protected void postAndWait(Runnable r) { + mHandler.post(r); + waitForFragments(); + } + + protected void waitForFragments() { + waitForIdleSync(mHandler); + } + + private View findViewById(int id) { + return mView.findViewById(id); + } + + private class HostCallbacks extends FragmentHostCallback<FragmentTestCase> { + public HostCallbacks() { + super(getTrackedContext(), FragmentTestCase.this.mHandler, 0); + } + + @Override + public FragmentTestCase onGetHost() { + return FragmentTestCase.this; + } + + @Override + public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + } + + @Override + public boolean onShouldSaveFragmentState(Fragment fragment) { + return true; // True for now. + } + + @Override + public LayoutInflater onGetLayoutInflater() { + return LayoutInflater.from(mContext); + } + + @Override + public boolean onUseFragmentManagerInflaterFactory() { + return true; + } + + @Override + public boolean onHasWindowAnimations() { + return false; + } + + @Override + public int onGetWindowAnimations() { + return 0; + } + + @Override + public void onAttachFragment(Fragment fragment) { + } + + @Nullable + @Override + public View onFindViewById(int id) { + return FragmentTestCase.this.findViewById(id); + } + + @Override + public boolean onHasView() { + return true; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java new file mode 100644 index 000000000000..d64669d66049 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.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.systemui; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.BroadcastReceiver; +import android.content.ComponentCallbacks; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.systemui.statusbar.phone.ManagedProfileController; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.CastController; +import com.android.systemui.statusbar.policy.DataSaverController; +import com.android.systemui.statusbar.policy.FlashlightController; +import com.android.systemui.statusbar.policy.HotspotController; +import com.android.systemui.statusbar.policy.KeyguardMonitor; +import com.android.systemui.statusbar.policy.LocationController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.SecurityController; +import com.android.systemui.statusbar.policy.CallbackController; +import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.ZenModeController; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Base class for tests to check if receivers are left registered, services bound, or other + * listeners listening. + */ +public class LeakCheckedTest extends SysuiTestCase { + private static final String TAG = "LeakCheckedTest"; + + private final Map<String, Tracker> mTrackers = new HashMap<>(); + private final Map<Class, Object> mLeakCheckers = new ArrayMap<>(); + private TrackingContext mTrackedContext; + + @Rule + public TestWatcher successWatcher = new TestWatcher() { + @Override + protected void succeeded(Description description) { + verify(); + } + }; + + @Before + public void setup() { + mTrackedContext = new TrackingContext(mContext); + addSupportedLeakCheckers(); + } + + public <T> T getLeakChecker(Class<T> cls) { + T obj = (T) mLeakCheckers.get(cls); + if (obj == null) { + Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet"); + } + return obj; + } + + public Context getTrackedContext() { + return mTrackedContext; + } + + private Tracker getTracker(String tag) { + Tracker t = mTrackers.get(tag); + if (t == null) { + t = new Tracker(); + mTrackers.put(tag, t); + } + return t; + } + + public void verify() { + mTrackers.values().forEach(Tracker::verify); + } + + public static class Tracker { + private Map<Object, LeakInfo> mObjects = new ArrayMap<>(); + + LeakInfo getLeakInfo(Object object) { + LeakInfo leakInfo = mObjects.get(object); + if (leakInfo == null) { + leakInfo = new LeakInfo(); + mObjects.put(object, leakInfo); + } + return leakInfo; + } + + private void verify() { + mObjects.values().forEach(LeakInfo::verify); + } + } + + public static class LeakInfo { + private List<Throwable> mThrowables = new ArrayList<>(); + + private LeakInfo() { + } + + private void addAllocation(Throwable t) { + // TODO: Drop off the first element in the stack trace here to have a cleaner stack. + mThrowables.add(t); + } + + private void clearAllocations() { + mThrowables.clear(); + } + + public void verify() { + if (mThrowables.size() == 0) return; + Log.e(TAG, "Listener or binding not properly released"); + for (Throwable t : mThrowables) { + Log.e(TAG, "Allocation found", t); + } + StringWriter writer = new StringWriter(); + mThrowables.get(0).printStackTrace(new PrintWriter(writer)); + Assert.fail("Listener or binding not properly released\n" + + writer.toString()); + } + } + + private void addSupportedLeakCheckers() { + addListening("bluetooth", BluetoothController.class); + addListening("location", LocationController.class); + addListening("rotation", RotationLockController.class); + addListening("zen", ZenModeController.class); + addListening("cast", CastController.class); + addListening("hotspot", HotspotController.class); + addListening("flashlight", FlashlightController.class); + addListening("user", UserInfoController.class); + addListening("keyguard", KeyguardMonitor.class); + addListening("battery", BatteryController.class); + addListening("security", SecurityController.class); + addListening("profile", ManagedProfileController.class); + addListening("alarm", NextAlarmController.class); + NetworkController network = addListening("network", NetworkController.class); + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + getTracker("emergency").getLeakInfo(invocation.getArguments()[0]) + .addAllocation(new Throwable()); + return null; + } + }).when(network).addEmergencyListener(any()); + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + getTracker("emergency").getLeakInfo(invocation.getArguments()[0]).clearAllocations(); + return null; + } + }).when(network).removeEmergencyListener(any()); + DataSaverController datasaver = addListening("datasaver", DataSaverController.class); + when(network.getDataSaverController()).thenReturn(datasaver); + } + + private <T extends CallbackController> T addListening(final String tag, Class<T> cls) { + T mock = mock(cls); + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + getTracker(tag).getLeakInfo(invocation.getArguments()[0]) + .addAllocation(new Throwable()); + return null; + } + }).when(mock).addCallback(any()); + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations(); + return null; + } + }).when(mock).removeCallback(any()); + mLeakCheckers.put(cls, mock); + return mock; + } + + class TrackingContext extends ContextWrapper { + public TrackingContext(Context base) { + super(base); + } + + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { + getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable()); + return super.registerReceiver(receiver, filter); + } + + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, + String broadcastPermission, Handler scheduler) { + getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable()); + return super.registerReceiver(receiver, filter, broadcastPermission, scheduler); + } + + @Override + public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, + IntentFilter filter, String broadcastPermission, Handler scheduler) { + getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable()); + return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, + scheduler); + } + + @Override + public void unregisterReceiver(BroadcastReceiver receiver) { + getTracker("receiver").getLeakInfo(receiver).clearAllocations(); + super.unregisterReceiver(receiver); + } + + @Override + public boolean bindService(Intent service, ServiceConnection conn, int flags) { + getTracker("service").getLeakInfo(conn).addAllocation(new Throwable()); + return super.bindService(service, conn, flags); + } + + @Override + public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, + Handler handler, UserHandle user) { + getTracker("service").getLeakInfo(conn).addAllocation(new Throwable()); + return super.bindServiceAsUser(service, conn, flags, handler, user); + } + + @Override + public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, + UserHandle user) { + getTracker("service").getLeakInfo(conn).addAllocation(new Throwable()); + return super.bindServiceAsUser(service, conn, flags, user); + } + + @Override + public void unbindService(ServiceConnection conn) { + getTracker("service").getLeakInfo(conn).clearAllocations(); + super.unbindService(conn); + } + + @Override + public void registerComponentCallbacks(ComponentCallbacks callback) { + getTracker("component").getLeakInfo(callback).addAllocation(new Throwable()); + super.registerComponentCallbacks(callback); + } + + @Override + public void unregisterComponentCallbacks(ComponentCallbacks callback) { + getTracker("component").getLeakInfo(callback).clearAllocations(); + super.unregisterComponentCallbacks(callback); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index d943eb6a1a60..5dac8e54aa21 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -20,6 +20,10 @@ import android.support.test.InstrumentationRegistry; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; + +import com.android.systemui.utils.TestableContext; + +import org.junit.After; import org.junit.Before; /** @@ -28,11 +32,16 @@ import org.junit.Before; public class SysuiTestCase { private Handler mHandler; - protected Context mContext; + protected TestableContext mContext; @Before public void SysuiSetup() throws Exception { - mContext = InstrumentationRegistry.getTargetContext(); + mContext = new TestableContext(InstrumentationRegistry.getTargetContext()); + } + + @After + public void cleanup() throws Exception { + mContext.getSettingsProvider().clearOverrides(this); } protected Context getContext() { 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/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java index 39b64129f64d..5c87fb01e23c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java @@ -17,9 +17,11 @@ package com.android.systemui.power; import static android.test.MoreAsserts.assertNotEqual; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -29,9 +31,11 @@ import static org.mockito.Mockito.verify; import android.app.Notification; import android.app.NotificationManager; -import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; + +import com.android.systemui.SysuiTestCase; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,7 +43,7 @@ import org.mockito.ArgumentCaptor; @SmallTest @RunWith(AndroidJUnit4.class) -public class PowerNotificationWarningsTest { +public class PowerNotificationWarningsTest extends SysuiTestCase { private final NotificationManager mMockNotificationManager = mock(NotificationManager.class); private PowerNotificationWarnings mPowerNotificationWarnings; @@ -47,7 +51,7 @@ public class PowerNotificationWarningsTest { public void setUp() throws Exception { // Test Instance. mPowerNotificationWarnings = new PowerNotificationWarnings( - InstrumentationRegistry.getTargetContext(), mMockNotificationManager, null); + mContext, mMockNotificationManager, null); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java new file mode 100644 index 000000000000..6ceaeada2643 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.qs; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.os.Handler; +import android.support.test.runner.AndroidJUnit4; + +import com.android.systemui.FragmentTestCase; +import com.android.systemui.statusbar.phone.PhoneStatusBar; +import com.android.systemui.statusbar.phone.QSTileHost; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.CastController; +import com.android.systemui.statusbar.policy.FlashlightController; +import com.android.systemui.statusbar.policy.HotspotController; +import com.android.systemui.statusbar.policy.KeyguardMonitor; +import com.android.systemui.statusbar.policy.LocationController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.SecurityController; +import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +public class QSFragmentTest extends FragmentTestCase { + + public QSFragmentTest() { + super(QSFragment.class); + } + + @Test + public void testListening() { + QSFragment qs = (QSFragment) mFragment; + postAndWait(() -> mFragments.dispatchResume()); + UserSwitcherController userSwitcher = mock(UserSwitcherController.class); + KeyguardMonitor keyguardMonitor = getLeakChecker(KeyguardMonitor.class); + when(userSwitcher.getKeyguardMonitor()).thenReturn(keyguardMonitor); + when(userSwitcher.getUsers()).thenReturn(new ArrayList<>()); + QSTileHost host = new QSTileHost(getTrackedContext(), + mock(PhoneStatusBar.class), + getLeakChecker(BluetoothController.class), + getLeakChecker(LocationController.class), + getLeakChecker(RotationLockController.class), + getLeakChecker(NetworkController.class), + getLeakChecker(ZenModeController.class), + getLeakChecker(HotspotController.class), + getLeakChecker(CastController.class), + getLeakChecker(FlashlightController.class), + userSwitcher, + getLeakChecker(UserInfoController.class), + keyguardMonitor, + getLeakChecker(SecurityController.class), + getLeakChecker(BatteryController.class), + mock(StatusBarIconController.class), + getLeakChecker(NextAlarmController.class)); + qs.setHost(host); + Handler h = new Handler(host.getLooper()); + + qs.setListening(true); + waitForIdleSync(h); + + qs.setListening(false); + waitForIdleSync(h); + + host.destroy(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java index 8eecfcf00d46..5401c30def54 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java @@ -18,6 +18,7 @@ package com.android.systemui.qs; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; @@ -26,11 +27,12 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.content.Context; -import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; + import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -38,13 +40,13 @@ import org.mockito.ArgumentCaptor; @SmallTest @RunWith(AndroidJUnit4.class) -public class TileLayoutTest { - private Context mContext = InstrumentationRegistry.getTargetContext(); - private final TileLayout mTileLayout = new TileLayout(mContext); +public class TileLayoutTest extends SysuiTestCase { + private TileLayout mTileLayout; private int mLayoutSizeForOneTile; @Before public void setUp() throws Exception { + mTileLayout = new TileLayout(mContext); // Layout needs to leave space for the tile margins. Three times the margin size is // sufficient for any number of columns. mLayoutSizeForOneTile = diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java index d7ff04f539ab..782a4890ba55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java @@ -16,7 +16,7 @@ package com.android.systemui.qs.external; import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -25,12 +25,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.Service; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageInfo; import android.content.pm.ServiceInfo; @@ -38,19 +35,16 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Process; -import android.os.RemoteException; import android.os.UserHandle; import android.service.quicksettings.IQSService; import android.service.quicksettings.IQSTileService; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; -import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; -import android.util.ArraySet; -import android.util.Log; + +import com.android.systemui.SysuiTestCase; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -61,7 +55,7 @@ import org.mockito.stubbing.Answer; @SmallTest @RunWith(AndroidJUnit4.class) -public class TileLifecycleManagerTest { +public class TileLifecycleManagerTest extends SysuiTestCase { private static final int TEST_FAIL_TIMEOUT = 5000; private final Context mMockContext = Mockito.mock(Context.class); @@ -78,8 +72,7 @@ public class TileLifecycleManagerTest { @Before public void setUp() throws Exception { setPackageEnabled(true); - mTileServiceComponentName = new ComponentName( - InstrumentationRegistry.getTargetContext(), "FakeTileService.class"); + mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class"); // Stub.asInterface will just return itself. when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService); diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java new file mode 100644 index 000000000000..74b612744870 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.recents.grid; + +import android.graphics.Rect; +import android.test.suitebuilder.annotation.SmallTest; +import com.android.systemui.SysuiTestCase; + +import java.util.List; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +@SmallTest +public class TaskGridLayoutAlgorithmTest extends SysuiTestCase { + + public void testMethodName_ExpectedBehavior() { + assertTrue(true); + } + + public void testOneTile() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 1, 1000, 500, false /* allowLineOfThree */, 0 /* padding */); + assertEquals(1, rects.size()); + Rect singleRect = rects.get(0); + assertEquals(1000, singleRect.width()); + } + + public void testTwoTilesLandscape() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 2, 1200, 500, false /* allowLineOfThree */, 0 /* padding */); + assertEquals(2, rects.size()); + for (Rect rect : rects) { + assertEquals(600, rect.width()); + assertEquals(500, rect.height()); + } + } + + public void testTwoTilesLandscapeWithPadding() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 2, 1200, 500, false /* allowLineOfThree */, 10 /* padding */); + assertEquals(2, rects.size()); + Rect rectA = rects.get(0); + Rect rectB = rects.get(1); + assertEquals(595, rectA.width()); + assertEquals(595, rectB.width()); + assertEquals(605, rectB.left); + } + + public void testTwoTilesPortrait() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 2, 500, 1200, false /* allowLineOfThree */, 0 /* padding */); + assertEquals(2, rects.size()); + for (Rect rect : rects) { + assertEquals(500, rect.width()); + assertEquals(600, rect.height()); + } + } + + public void testThreeTiles() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 3, 1200, 500, false /* allowLineOfThree */, 0 /* padding */); + assertEquals(3, rects.size()); + for (Rect rect : rects) { + assertEquals(600, rect.width()); + assertEquals(250, rect.height()); + } + // The third tile should be on the second line, in the middle. + Rect rectC = rects.get(2); + assertEquals(300, rectC.left); + assertEquals(250, rectC.top); + } + + public void testFourTiles() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 4, 1200, 500, false /* allowLineOfThree */, 0 /* padding */); + assertEquals(4, rects.size()); + for (Rect rect : rects) { + assertEquals(600, rect.width()); + assertEquals(250, rect.height()); + } + Rect rectD = rects.get(3); + assertEquals(600, rectD.left); + assertEquals(250, rectD.top); + } + + public void testNineTiles() { + List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 9, 1200, 600, false /* allowLineOfThree */, 0 /* padding */); + assertEquals(9, rects.size()); + for (Rect rect : rects) { + assertEquals(400, rect.width()); + assertEquals(200, rect.height()); + } + Rect rectE = rects.get(4); + assertEquals(400, rectE.left); + assertEquals(200, rectE.top); + Rect rectI = rects.get(8); + assertEquals(800, rectI.left); + assertEquals(400, rectI.top); + }} + diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 6c9cfe04ed80..136e7c0bc7a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -35,7 +35,7 @@ import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults; import com.android.systemui.SysuiTestCase; -import org.junit.After; + import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestWatcher; @@ -118,7 +118,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { // Trigger blank callbacks to always get the current state (some tests don't trigger // changes from default state). - mNetworkController.addSignalCallback(mock(SignalCallback.class)); + mNetworkController.addCallback(mock(SignalCallback.class)); mNetworkController.addEmergencyListener(null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java new file mode 100644 index 000000000000..34f2e019761d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.utils; + +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.Context; +import android.content.IContentProvider; +import android.database.ContentObserver; +import android.net.Uri; +import android.util.ArraySet; + +import com.google.android.collect.Maps; + +import java.util.Map; + +/** + * Alternative to a MockContentResolver that falls back to real providers. + */ +public class FakeContentResolver extends ContentResolver { + + private final Map<String, ContentProvider> mProviders = Maps.newHashMap(); + private final ContentResolver mParent; + private final ArraySet<ContentProvider> mInUse = new ArraySet<>(); + private boolean mFallbackToExisting; + + public FakeContentResolver(Context context) { + super(context); + mParent = context.getContentResolver(); + mFallbackToExisting = true; + } + + /** + * Sets whether existing providers should be returned when a mock does not exist. + * The default is true. + */ + public void setFallbackToExisting(boolean fallbackToExisting) { + mFallbackToExisting = fallbackToExisting; + } + + /** + * Adds access to a provider based on its authority + * + * @param name The authority name associated with the provider. + * @param provider An instance of {@link android.content.ContentProvider} or one of its + * subclasses, or null. + */ + public void addProvider(String name, ContentProvider provider) { + mProviders.put(name, provider); + } + + @Override + protected IContentProvider acquireProvider(Context context, String name) { + final ContentProvider provider = mProviders.get(name); + if (provider != null) { + return provider.getIContentProvider(); + } else { + return mFallbackToExisting ? mParent.acquireProvider(name) : null; + } + } + + @Override + protected IContentProvider acquireExistingProvider(Context context, String name) { + final ContentProvider provider = mProviders.get(name); + if (provider != null) { + return provider.getIContentProvider(); + } else { + return mFallbackToExisting ? mParent.acquireExistingProvider( + new Uri.Builder().authority(name).build()) : null; + } + } + + @Override + public boolean releaseProvider(IContentProvider provider) { + if (!mFallbackToExisting) return true; + if (mInUse.contains(provider)) { + mInUse.remove(provider); + return true; + } + return mParent.releaseProvider(provider); + } + + @Override + protected IContentProvider acquireUnstableProvider(Context c, String name) { + final ContentProvider provider = mProviders.get(name); + if (provider != null) { + return provider.getIContentProvider(); + } else { + return mFallbackToExisting ? mParent.acquireUnstableProvider(name) : null; + } + } + + @Override + public boolean releaseUnstableProvider(IContentProvider icp) { + if (!mFallbackToExisting) return true; + if (mInUse.contains(icp)) { + mInUse.remove(icp); + return true; + } + return mParent.releaseUnstableProvider(icp); + } + + @Override + public void unstableProviderDied(IContentProvider icp) { + if (!mFallbackToExisting) return; + if (mInUse.contains(icp)) { + return; + } + mParent.unstableProviderDied(icp); + } + + @Override + public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { + if (!mFallbackToExisting) return; + if (!mProviders.containsKey(uri.getAuthority())) { + super.notifyChange(uri, observer, syncToNetwork); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java new file mode 100644 index 000000000000..f40fe4cb2450 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.utils; + +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.os.Bundle; +import android.os.RemoteException; +import android.provider.Settings; +import android.support.annotation.VisibleForTesting; +import android.test.mock.MockContentProvider; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider.Builder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Allows calls to android.provider.Settings to be tested easier. A SettingOverride + * can be acquired and a set of specific settings can be set to a value (and not changed + * in the system when set), so that they can be tested without breaking the test device. + * <p> + * To use, in the before method acquire the override add all settings that will affect if + * your test passes or not. + * + * <pre class="prettyprint"> + * {@literal + * mSettingOverride = mTestableContext.getSettingsProvider().acquireOverridesBuilder() + * .addSetting("secure", Secure.USER_SETUP_COMPLETE, "0") + * .build(); + * } + * </pre> + * + * Then in the after free up the settings. + * + * <pre class="prettyprint"> + * {@literal + * mSettingOverride.release(); + * } + * </pre> + */ +public class FakeSettingsProvider extends MockContentProvider { + + private static final String TAG = "FakeSettingsProvider"; + private static final boolean DEBUG = false; + + // Number of times to try to acquire a setting if in use. + private static final int MAX_TRIES = 10; + // Time to wait for each setting. WAIT_TIMEOUT * MAX_TRIES will be the maximum wait time + // for a setting. + private static final long WAIT_TIMEOUT = 1000; + + private final Map<String, SettingOverrider> mOverrideMap = new ArrayMap<>(); + private final Map<SysuiTestCase, List<SettingOverrider>> mOwners = new ArrayMap<>(); + + private static FakeSettingsProvider sInstance; + private final ContentProviderClient mSettings; + private final ContentResolver mResolver; + + private FakeSettingsProvider(ContentProviderClient settings, ContentResolver resolver) { + mSettings = settings; + mResolver = resolver; + } + + public Builder acquireOverridesBuilder(SysuiTestCase test) { + return new Builder(this, test); + } + + public void clearOverrides(SysuiTestCase test) { + List<SettingOverrider> overrides = mOwners.remove(test); + if (overrides != null) { + overrides.forEach(override -> override.ensureReleased()); + } + } + + public Bundle call(String method, String arg, Bundle extras) { + // Methods are "GET_system", "GET_global", "PUT_secure", etc. + final String[] commands = method.split("_", 2); + final String op = commands[0]; + final String table = commands[1]; + + synchronized (mOverrideMap) { + SettingOverrider overrider = mOverrideMap.get(key(table, arg)); + if (overrider == null) { + // Fall through to real settings. + try { + if (DEBUG) Log.d(TAG, "Falling through to real settings " + method); + // TODO: Add our own version of caching to handle this. + Bundle call = mSettings.call(method, arg, extras); + call.remove(Settings.CALL_METHOD_TRACK_GENERATION_KEY); + return call; + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + String value; + Bundle out = new Bundle(); + switch (op) { + case "GET": + value = overrider.get(table, arg); + if (value != null) { + out.putString(Settings.NameValueTable.VALUE, value); + } + break; + case "PUT": + value = extras.getString(Settings.NameValueTable.VALUE, null); + if (value != null) { + overrider.put(table, arg, value); + } else { + overrider.remove(table, arg); + } + break; + default: + throw new UnsupportedOperationException("Unknown command " + method); + } + return out; + } + } + + private void acquireSettings(SettingOverrider overridder, Set<String> keys, + SysuiTestCase owner) throws AcquireTimeoutException { + synchronized (mOwners) { + List<SettingOverrider> list = mOwners.get(owner); + if (list == null) { + list = new ArrayList<>(); + mOwners.put(owner, list); + } + list.add(overridder); + } + synchronized (mOverrideMap) { + for (int i = 0; i < MAX_TRIES; i++) { + if (checkKeys(keys, false)) break; + try { + if (DEBUG) Log.d(TAG, "Waiting for contention to finish"); + mOverrideMap.wait(WAIT_TIMEOUT); + } catch (InterruptedException e) { + } + } + checkKeys(keys, true); + for (String key : keys) { + if (DEBUG) Log.d(TAG, "Acquiring " + key); + mOverrideMap.put(key, overridder); + } + } + } + + private void releaseSettings(Set<String> keys) { + synchronized (mOverrideMap) { + for (String key : keys) { + if (DEBUG) Log.d(TAG, "Releasing " + key); + mOverrideMap.remove(key); + } + if (DEBUG) Log.d(TAG, "Notifying"); + mOverrideMap.notify(); + } + } + + @VisibleForTesting + public Object getLock() { + return mOverrideMap; + } + + private boolean checkKeys(Set<String> keys, boolean shouldThrow) + throws AcquireTimeoutException { + for (String key : keys) { + if (mOverrideMap.containsKey(key)) { + if (shouldThrow) { + throw new AcquireTimeoutException("Could not acquire " + key); + } + return false; + } + } + return true; + } + + public static class SettingOverrider { + private final Set<String> mValidKeys; + private final Map<String, String> mValueMap = new ArrayMap<>(); + private final FakeSettingsProvider mProvider; + private boolean mReleased; + + private SettingOverrider(Set<String> keys, FakeSettingsProvider provider) { + mValidKeys = new ArraySet<>(keys); + mProvider = provider; + } + + private void ensureReleased() { + if (!mReleased) { + release(); + } + } + + public void release() { + mProvider.releaseSettings(mValidKeys); + mReleased = true; + } + + private void putDirect(String key, String value) { + mValueMap.put(key, value); + } + + public void put(String table, String key, String value) { + if (!mValidKeys.contains(key(table, key))) { + throw new IllegalArgumentException("Key " + table + " " + key + + " not acquired for this overrider"); + } + mValueMap.put(key(table, key), value); + } + + public void remove(String table, String key) { + if (!mValidKeys.contains(key(table, key))) { + throw new IllegalArgumentException("Key " + table + " " + key + + " not acquired for this overrider"); + } + mValueMap.remove(key(table, key)); + } + + public String get(String table, String key) { + if (!mValidKeys.contains(key(table, key))) { + throw new IllegalArgumentException("Key " + table + " " + key + + " not acquired for this overrider"); + } + Log.d(TAG, "Get " + table + " " + key + " " + mValueMap.get(key(table, key))); + return mValueMap.get(key(table, key)); + } + + public static class Builder { + private final FakeSettingsProvider mProvider; + private final SysuiTestCase mOwner; + private Set<String> mKeys = new ArraySet<>(); + private Map<String, String> mValues = new ArrayMap<>(); + + private Builder(FakeSettingsProvider provider, SysuiTestCase test) { + mProvider = provider; + mOwner = test; + } + + public Builder addSetting(String table, String key) { + mKeys.add(key(table, key)); + return this; + } + + public Builder addSetting(String table, String key, String value) { + addSetting(table, key); + mValues.put(key(table, key), value); + return this; + } + + public SettingOverrider build() throws AcquireTimeoutException { + SettingOverrider overrider = new SettingOverrider(mKeys, mProvider); + mProvider.acquireSettings(overrider, mKeys, mOwner); + mValues.forEach((key, value) -> overrider.putDirect(key, value)); + return overrider; + } + } + } + + public static class AcquireTimeoutException extends Exception { + public AcquireTimeoutException(String str) { + super(str); + } + } + + private static String key(String table, String key) { + return table + "_" + key; + } + + /** + * Since the settings provider is cached inside android.provider.Settings, this must + * be gotten statically to ensure there is only one instance referenced. + * @param settings + */ + public static FakeSettingsProvider getFakeSettingsProvider(ContentProviderClient settings, + ContentResolver resolver) { + if (sInstance == null) { + sInstance = new FakeSettingsProvider(settings, resolver); + } + return sInstance; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java new file mode 100644 index 000000000000..63bb5e7f0e4a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.content.ContentResolver; +import android.os.Handler; +import android.os.HandlerThread; +import android.provider.Settings; +import android.provider.Settings.Global; +import android.provider.Settings.Secure; +import android.support.test.runner.AndroidJUnit4; +import android.util.Log; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.utils.FakeSettingsProvider.AcquireTimeoutException; +import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class FakeSettingsProviderTest extends SysuiTestCase { + + public static final String NONEXISTENT_SETTING = "nonexistent_setting"; + private static final String TAG = "FakeSettingsProviderTest"; + private SettingOverrider mOverrider; + private ContentResolver mContentResolver; + + @Before + public void setup() throws AcquireTimeoutException { + mOverrider = mContext.getSettingsProvider().acquireOverridesBuilder(this) + .addSetting("secure", NONEXISTENT_SETTING) + .addSetting("global", NONEXISTENT_SETTING, "initial value") + .addSetting("global", Global.DEVICE_PROVISIONED) + .build(); + mContentResolver = mContext.getContentResolver(); + } + + @After + public void teardown() { + if (mOverrider != null) { + mOverrider.release(); + } + } + + @Test + public void testInitialValueSecure() { + String value = Secure.getString(mContentResolver, NONEXISTENT_SETTING); + assertNull(value); + } + + @Test + public void testInitialValueGlobal() { + String value = Global.getString(mContentResolver, NONEXISTENT_SETTING); + assertEquals("initial value", value); + } + + @Test + public void testSeparateTables() { + Secure.putString(mContentResolver, NONEXISTENT_SETTING, "something"); + Global.putString(mContentResolver, NONEXISTENT_SETTING, "else"); + assertEquals("something", Secure.getString(mContentResolver, NONEXISTENT_SETTING)); + assertEquals("something", mOverrider.get("secure", NONEXISTENT_SETTING)); + assertEquals("else", Global.getString(mContentResolver, NONEXISTENT_SETTING)); + assertEquals("else", mOverrider.get("global", NONEXISTENT_SETTING)); + } + + @Test + public void testPassThrough() { + // Grab the value of a setting that is not overridden. + assertTrue(Secure.getInt(mContentResolver, Secure.USER_SETUP_COMPLETE, 0) != 0); + } + + @Test + public void testOverrideExisting() { + // Grab the value of a setting that is overridden and will be different than the actual + // value. + assertNull(Global.getString(mContentResolver, Global.DEVICE_PROVISIONED)); + } + + @Test + public void testRelease() { + // Verify different value. + assertNull(Global.getString(mContentResolver, Global.DEVICE_PROVISIONED)); + mOverrider.release(); + mOverrider = null; + // Verify actual value after release. + assertEquals("1", Global.getString(mContentResolver, Global.DEVICE_PROVISIONED)); + } + + @Test + public void testAutoRelease() throws Exception { + super.cleanup(); + mContext.getSettingsProvider().acquireOverridesBuilder(this) + .addSetting("global", Global.DEVICE_PROVISIONED) + .build(); + } + + @Test + public void testContention() throws AcquireTimeoutException, InterruptedException { + SettingOverrider[] overriders = new SettingOverrider[2]; + Object lock = new Object(); + String secure = "secure"; + String key = "something shared"; + String[] result = new String[1]; + overriders[0] = mContext.getSettingsProvider().acquireOverridesBuilder(this) + .addSetting(secure, key, "Some craziness") + .build(); + synchronized (lock) { + HandlerThread t = runOnHandler(() -> { + try { + // Grab the lock that will be used for the settings ownership to ensure + // we have some contention going on. + synchronized (mContext.getSettingsProvider().getLock()) { + synchronized (lock) { + // Let the other thread know to release the settings, but it won't + // be able to until this thread waits in the build() method. + lock.notify(); + } + overriders[1] = mContext.getSettingsProvider() + .acquireOverridesBuilder(FakeSettingsProviderTest.this) + .addSetting(secure, key, "default value") + .build(); + // Ensure that the default is the one we set, and not left over from + // the other setting override. + result[0] = Settings.Secure.getString(mContentResolver, key); + synchronized (lock) { + // Let the main thread know we are done. + lock.notify(); + } + } + } catch (AcquireTimeoutException e) { + Log.e(TAG, "Couldn't acquire setting", e); + } + }); + // Wait for the thread to hold the acquire lock, then release the settings. + lock.wait(); + overriders[0].release(); + // Wait for the thread to be done getting the value. + lock.wait(); + // Quit and cleanup. + t.quitSafely(); + assertNotNull(overriders[1]); + overriders[1].release(); + } + // Verify the value was the expected one from the thread's SettingOverride. + assertEquals("default value", result[0]); + } + + private HandlerThread runOnHandler(Runnable r) { + HandlerThread t = new HandlerThread("Test Thread"); + t.start(); + new Handler(t.getLooper()).post(r); + return t; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java new file mode 100644 index 000000000000..517982361424 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.utils; + +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.content.Context; +import android.content.ContextWrapper; +import android.provider.Settings; + +public class TestableContext extends ContextWrapper { + + private final FakeContentResolver mFakeContentResolver; + private final FakeSettingsProvider mSettingsProvider; + + public TestableContext(Context base) { + super(base); + mFakeContentResolver = new FakeContentResolver(base); + ContentProviderClient settings = base.getContentResolver() + .acquireContentProviderClient(Settings.AUTHORITY); + mSettingsProvider = FakeSettingsProvider.getFakeSettingsProvider(settings, + mFakeContentResolver); + mFakeContentResolver.addProvider(Settings.AUTHORITY, mSettingsProvider); + } + + public FakeSettingsProvider getSettingsProvider() { + return mSettingsProvider; + } + + @Override + public FakeContentResolver getContentResolver() { + return mFakeContentResolver; + } + + @Override + public Context getApplicationContext() { + // Return this so its always a TestableContext. + return this; + } +} diff --git a/preloaded-classes b/preloaded-classes index 45734b6861c0..a79ae5098098 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -327,9 +327,6 @@ android.app.ActivityManager$RunningAppProcessInfo$1 android.app.ActivityManager$StackId android.app.ActivityManager$TaskDescription android.app.ActivityManager$TaskDescription$1 -android.app.ActivityManagerNative -android.app.ActivityManagerNative$1 -android.app.ActivityManagerProxy android.app.ActivityOptions android.app.ActivityThread android.app.ActivityThread$1 @@ -1729,9 +1726,9 @@ android.os.UserManager android.os.Vibrator android.os.ZygoteStartFailedEx android.os.health.SystemHealthManager -android.os.storage.IMountService -android.os.storage.IMountService$Stub -android.os.storage.IMountService$Stub$Proxy +android.os.storage.IStorageManager +android.os.storage.IStorageManager$Stub +android.os.storage.IStorageManager$Stub$Proxy android.os.storage.StorageManager android.os.storage.StorageVolume android.os.storage.StorageVolume$1 diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 48bc27e1c440..45f2ec76588a 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -22,6 +22,27 @@ package com_android_internal_logging; // Wrapper for System UI log events message MetricsEvent { + // Types of events + enum Type { + // Unknown + TYPE_UNKNOWN = 0; + + // The view became visible to the user. + TYPE_OPEN = 1; + + // The view became hidden. + TYPE_CLOSE = 2; + + // The view switched to detail mode (most relevant for quick settings tiles) + TYPE_DETAIL = 3; + + // The view or control was activated. + TYPE_ACTION = 4; + + // The view or control was dismissed. + TYPE_DISMISS = 5; + } + // Known visual elements: views or controls. enum View { // Unknown view @@ -2627,6 +2648,17 @@ message MetricsEvent { // ACTION: Logs the end to end time taken by all provisioning tasks. PROVISIONING_TOTAL_TASK_TIME_MS = 627; + // OPEN: Settings > Privacy + // CATEGORY: SETTINGS + // 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/Android.mk b/services/Android.mk index 3385bed0ba8b..291198303548 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -22,6 +22,7 @@ services := \ core \ accessibility \ appwidget \ + autofill \ backup \ devicepolicy \ midi \ diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index bf60e4711c3b..6404604ca097 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -1593,14 +1593,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(callingPackage); - - final int bitmapMemoryUsage = (views != null) ? views.estimateMemoryUsage() : 0; - if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) { - throw new IllegalArgumentException("RemoteViews for widget update exceeds" - + " maximum bitmap memory usage (used: " + bitmapMemoryUsage - + ", max: " + mMaxWidgetBitmapMemory + ")"); - } - synchronized (mLock) { ensureGroupStateLoadedLocked(userId); @@ -1812,6 +1804,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // For a full update we replace the RemoteViews completely. widget.views = views; } + int memoryUsage; + if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) && + (widget.views != null) && + ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) { + widget.views = null; + throw new IllegalArgumentException("RemoteViews for widget update exceeds" + + " maximum bitmap memory usage (used: " + memoryUsage + + ", max: " + mMaxWidgetBitmapMemory + ")"); + } scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked()); } } diff --git a/services/autofill/Android.mk b/services/autofill/Android.mk new file mode 100644 index 000000000000..a1f19fd4c72d --- /dev/null +++ b/services/autofill/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.autofill + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +LOCAL_JAVA_LIBRARIES := services.core + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java new file mode 100644 index 000000000000..d70c4391e274 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java @@ -0,0 +1,441 @@ +/* + * 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.autofill; + +import static android.Manifest.permission.MANAGE_AUTO_FILL; +import static android.content.Context.AUTO_FILL_MANAGER_SERVICE; + +import android.Manifest; +import android.app.AppGlobals; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +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.PackageManager; +import android.content.pm.ServiceInfo; +import android.content.pm.UserInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.os.SystemClock; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.service.autofill.IAutoFillManagerService; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; +import android.util.TimeUtils; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.BackgroundThread; +import com.android.server.FgThread; +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; + +/** + * Entry point service for auto-fill management. + * + * <p>This service provides the {@link IAutoFillManagerService} implementation and keeps a list of + * {@link AutoFillManagerServiceImpl} per user; the real work is done by + * {@link AutoFillManagerServiceImpl} itself. + */ +public final class AutoFillManagerService extends SystemService { + + private static final String TAG = "AutoFillManagerService"; + static final boolean DEBUG = true; // TODO: change to false once stable + + private static final long SERVICE_BINDING_LIFETIME_MS = 5 * DateUtils.MINUTE_IN_MILLIS; + + private static final int ARG_NOT_USED = 0; + + protected static final int MSG_UNBIND = 1; + + private final AutoFillManagerServiceStub mServiceStub; + private final Context mContext; + private final ContentResolver mResolver; + + private final Object mLock = new Object(); + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UNBIND: + removeStaleServiceForUser(msg.arg1); + return; + case MSG_SHOW_ALL_NOTIFICATIONS: + showAllNotifications(); + return; + default: + Slog.w(TAG, "Invalid message: " + msg); + } + } + + }; + + /** + * Cache of {@link AutoFillManagerServiceImpl} per user id. + * <p> + * It has to be mapped by user id because the same current user could have simultaneous sessions + * associated to different user profiles (for example, in a multi-window environment or when + * device has work profiles). + * <p> + * Entries on this cache are added on demand and removed when: + * <ol> + * <li>An auto-fill service app is removed. + * <li>The {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} for an user change. + * <li>It has not been interacted with for {@link #SERVICE_BINDING_LIFETIME_MS} ms. + * </ol> + */ + @GuardedBy("mLock") + private SparseArray<AutoFillManagerServiceImpl> mServicesCache = new SparseArray<>(); + + public AutoFillManagerService(Context context) { + super(context); + + mContext = context; + mResolver = context.getContentResolver(); + mServiceStub = new AutoFillManagerServiceStub(); + } + + @Override + public void onStart() { + if (DEBUG) Slog.d(TAG, "onStart(): binding as " + AUTO_FILL_MANAGER_SERVICE); + publishBinderService(AUTO_FILL_MANAGER_SERVICE, mServiceStub); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + new SettingsObserver(BackgroundThread.getHandler()); + } + if (phase == PHASE_BOOT_COMPLETED) { + // TODO: if sent right away, the notification is not displayed. Since the notification + // mechanism is a temporary approach anyways, just delay it.. + if (DEBUG) + Slog.d(TAG, "Showing notifications in " + SHOW_ALL_NOTIFICATIONS_DELAY_MS + "ms"); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ALL_NOTIFICATIONS), + SHOW_ALL_NOTIFICATIONS_DELAY_MS); + } + } + + private AutoFillManagerServiceImpl newServiceForUser(int userId) { + ComponentName serviceComponent = null; + ServiceInfo serviceInfo = null; + final String componentName = Settings.Secure.getStringForUser( + mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId); + if (!TextUtils.isEmpty(componentName)) { + try { + serviceComponent = ComponentName.unflattenFromString(componentName); + serviceInfo = + AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId); + } catch (RuntimeException | RemoteException e) { + Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e); + return null; + } + } + + if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component=" + + serviceComponent + ", info: " + serviceInfo); + if (serviceInfo == null) { + Slog.w(TAG, "no service info for " + serviceComponent); + return null; + } + return new AutoFillManagerServiceImpl(this, mContext, mLock, FgThread.getHandler(), userId, + serviceInfo.applicationInfo.uid, serviceComponent, SERVICE_BINDING_LIFETIME_MS); + } + + /** + * Gets the service instance for an user. + * + * <p>First it tries to return the existing instance from the cache; if it's not cached, it + * creates a new instance and caches it. + */ + private AutoFillManagerServiceImpl getServiceForUserLocked(int userId) { + AutoFillManagerServiceImpl service = mServicesCache.get(userId); + if (service != null) { + if (DEBUG) Log.d(TAG, "reusing cached service for userId " + userId); + service.setLifeExpectancy(SERVICE_BINDING_LIFETIME_MS); + } else { + service = newServiceForUser(userId); + if (service == null) { + // Already logged + return null; + } + if (DEBUG) Log.d(TAG, "creating new cached service for userId " + userId); + service.startLocked(); + mServicesCache.put(userId, service); + } + // Keep service connection alive for a while, in case user needs to interact with it + // (for example, to save the data that was inputted in) + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UNBIND, userId, ARG_NOT_USED), + SERVICE_BINDING_LIFETIME_MS); + return service; + } + + /** + * Removes a cached service, but respecting its TTL. + */ + private void removeStaleServiceForUser(int userId) { + synchronized (mLock) { + removeCachedService(userId, false); + } + } + + /** + * Removes a cached service, even if it has TTL. + */ + void removeCachedServiceForUserLocked(int userId) { + removeCachedService(userId, true); + } + + private void removeCachedService(int userId, boolean force) { + if (DEBUG) Log.d(TAG, "removing cached service for userId " + userId); + final AutoFillManagerServiceImpl service = mServicesCache.get(userId); + if (service == null) { + Log.w(TAG, "removeCachedServiceForUser(): no cached service for userId " + userId); + return; + } + if (!force) { + // Check TTL first. + final long now = SystemClock.uptimeMillis(); + if (service.mEstimateTimeOfDeath > now) { + if (DEBUG) { + final StringBuilder msg = new StringBuilder("service has some TTL left: "); + TimeUtils.formatDuration(service.mEstimateTimeOfDeath - now, msg); + Log.d(TAG, msg.toString()); + } + return; + } + } + mServicesCache.delete(userId); + service.stopLocked(); + + } + + final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub { + + @Override + public void requestAutoFill(int userId, IBinder activityToken) { + mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + + synchronized (mLock) { + final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + service.requestAutoFill(activityToken); + } + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingPermission( + Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump autofill from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + synchronized (mLock) { + final int size = mServicesCache.size(); + pw.print("Cached services: "); + if (size == 0) { + pw.println("none"); + } else { + pw.println(size); + for (int i = 0; i < size; i++) { + pw.print("\nService at index "); pw.println(i); + final AutoFillManagerServiceImpl impl = mServicesCache.valueAt(i); + impl.dumpLocked(" ", pw); + } + } + } + } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { + (new AutoFillManagerServiceShellCommand(this)).exec( + this, in, out, err, args, callback, resultReceiver); + } + + } + + private final class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.AUTO_FILL_SERVICE), false, this, UserHandle.USER_ALL); + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId); + synchronized (mLock) { + removeCachedServiceForUserLocked(userId); + final ComponentName serviceComponent = getProviderForUser(userId); + if (serviceComponent== null) { + cancelNotificationLocked(userId); + } else { + showNotification(serviceComponent, userId); + } + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // TODO: temporary code using a notification to request auto-fill. // + // Will be removed once UX decide the right way to present it to the user // + //////////////////////////////////////////////////////////////////////////// + + // TODO: remove from frameworks/base/core/res/AndroidManifest.xml once it's not used anymore + private static final String NOTIFICATION_INTENT = + "com.android.internal.autofill.action.REQUEST_AUTOFILL"; + private static final String EXTRA_USER_ID = "user_id"; + + private static final int MSG_SHOW_ALL_NOTIFICATIONS = 42; + private static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000; + + private BroadcastReceiver mNotificationReceiver; + + final class NotificationReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final int userId = intent.getIntExtra(EXTRA_USER_ID, -1); + if (DEBUG) Slog.d(TAG, "Requesting autofill by notification for user " + userId); + synchronized (mLock) { + final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId); + if (service == null) { + Slog.w(TAG, "no auto-fill service for user " + userId); + } else { + service.requestAutoFill(null); + } + } + } + } + + private ComponentName getProviderForUser(int userId) { + ComponentName serviceComponent = null; + ServiceInfo serviceInfo = null; + final String componentName = Settings.Secure.getStringForUser( + mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId); + if (!TextUtils.isEmpty(componentName)) { + try { + serviceComponent = ComponentName.unflattenFromString(componentName); + serviceInfo = + AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId); + } catch (RuntimeException | RemoteException e) { + Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e); + return null; + } + } + + if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component=" + + serviceComponent + ", info: " + serviceInfo); + if (serviceInfo == null) { + Slog.w(TAG, "no service info for " + serviceComponent); + return null; + } + return serviceComponent; + } + + private void showAllNotifications() { + final UserManager userManager = + (UserManager) mContext.getSystemService(Context.USER_SERVICE); + + final List<UserInfo> allUsers = userManager.getUsers(true); + + for (UserInfo user : allUsers) { + final ComponentName serviceComponent = getProviderForUser(user.id); + if (serviceComponent != null) { + showNotification(serviceComponent, user.id); + } + } + } + + private void showNotification(ComponentName serviceComponent, int userId) { + if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent); + + synchronized (mLock) { + if (mNotificationReceiver == null) { + mNotificationReceiver = new NotificationReceiver(); + mContext.registerReceiver(mNotificationReceiver, + new IntentFilter(NOTIFICATION_INTENT)); + } + } + + final Intent intent = new Intent(NOTIFICATION_INTENT); + intent.putExtra(EXTRA_USER_ID, userId); + final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + + final String packageName = serviceComponent.getPackageName(); + String providerName = null; + final PackageManager pm = mContext.getPackageManager(); + try { + final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId); + if (info != null) { + providerName = pm.getApplicationLabel(info).toString(); + } + } catch (Exception e) { + providerName = packageName; + } + final String title = "AutoFill by '" + providerName + "'"; + final String subTitle = "Tap notification to auto-fill top activity for user " + userId; + + final Notification notification = new Notification.Builder(mContext) + .setCategory(Notification.CATEGORY_SYSTEM) + .setOngoing(true) + .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) + .setLocalOnly(true) + .setColor(mContext.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setContentTitle(title) + .setStyle(new Notification.BigTextStyle().bigText(subTitle)) + .setContentIntent(pi) + .build(); + NotificationManager.from(mContext).notify(userId, notification); + } + + private void cancelNotificationLocked(int userId) { + if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId); + NotificationManager.from(mContext).cancel(userId); + } + + ///////////////////////////////////////// + // End of temporary notification code. // + ///////////////////////////////////////// +} diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java new file mode 100644 index 000000000000..e409cb072ef5 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java @@ -0,0 +1,325 @@ +/* + * 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.autofill; + +import static com.android.server.autofill.AutoFillManagerService.DEBUG; + +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.IActivityManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.icu.text.DateFormat; +import android.os.DeadObjectException; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.service.autofill.AutoFillService; +import android.service.autofill.AutoFillServiceInfo; +import android.service.autofill.IAutoFillService; +import android.util.Log; +import android.util.PrintWriterPrinter; +import android.util.Slog; +import android.util.TimeUtils; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.LocalServices; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +/** + * Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the + * app's {@link IAutoFillService} implementation. + * + */ +final class AutoFillManagerServiceImpl { + + private static final String TAG = "AutoFillManagerServiceImpl"; + + private final int mUserId; + private final int mUid; + private final ComponentName mComponent; + private final Context mContext; + private final IActivityManager mAm; + private final Object mLock; + private final AutoFillServiceInfo mInfo; + private final AutoFillManagerService mManagerService; + + // TODO: improve its usage + // - set maximum number of entries + // - disable on low-memory devices. + private final List<String> mRequestHistory = new LinkedList<>(); + + @GuardedBy("mLock") + private final List<IBinder> mQueuedRequests = new LinkedList<>(); + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + final String reason = intent.getStringExtra("reason"); + if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason); + // TODO: close any pending UI like account selection (or remove this receiver) + } + } + }; + + private final ServiceConnection mConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) Log.d(TAG, "onServiceConnected():" + name); + synchronized (mLock) { + mService = IAutoFillService.Stub.asInterface(service); + try { + mService.onConnected(); + } catch (RemoteException e) { + Slog.w(TAG, "Exception on service.onConnected(): " + e); + return; + } + if (!mQueuedRequests.isEmpty()) { + if (DEBUG) Log.d(TAG, "queued requests:" + mQueuedRequests.size()); + } + for (IBinder activityToken : mQueuedRequests) { + requestAutoFillLocked(activityToken, false); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (DEBUG) Log.d(TAG, name + " disconnected"); + synchronized (mLock) { + mService = null; + mManagerService.removeCachedServiceForUserLocked(mUserId); + } + } + }; + + @GuardedBy("mLock") + private IAutoFillService mService; + private boolean mBound; + private boolean mValid; + + // Estimated time when the service will be evicted from the cache. + long mEstimateTimeOfDeath; + + AutoFillManagerServiceImpl(AutoFillManagerService managerService, Context context, Object lock, + Handler handler, int userId, int uid,ComponentName component, long ttl) { + mManagerService = managerService; + mContext = context; + mLock = lock; + mUserId = userId; + mUid = uid; + mComponent = component; + mAm = ActivityManager.getService(); + setLifeExpectancy(ttl); + + final AutoFillServiceInfo info; + try { + info = new AutoFillServiceInfo(component, mUserId); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Auto-fill service not found: " + component, e); + mInfo = null; + mValid = false; + return; + } + mInfo = info; + if (mInfo.getParseError() != null) { + Slog.w(TAG, "Bad auto-fill service: " + mInfo.getParseError()); + mValid = false; + return; + } + + mValid = true; + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + mContext.registerReceiver(mBroadcastReceiver, filter, null, handler); + } + + void setLifeExpectancy(long ttl) { + mEstimateTimeOfDeath = SystemClock.uptimeMillis() + ttl; + } + + void startLocked() { + if (DEBUG) Slog.d(TAG, "startLocked()"); + + final Intent intent = new Intent(AutoFillService.SERVICE_INTERFACE); + intent.setComponent(mComponent); + mBound = mContext.bindServiceAsUser(intent, mConnection, + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUserId)); + + if (!mBound) { + Slog.w(TAG, "Failed binding to auto-fill service " + mComponent); + return; + } + if (DEBUG) Slog.d(TAG, "Bound to " + mComponent); + } + + void requestAutoFill(IBinder activityToken) { + synchronized (mLock) { + if (!mBound) { + Slog.w(TAG, "requestAutoFill() failed because it's not bound to service"); + return; + } + } + + // TODO: activityToken should probably not be null, but we need to wait until the UI is + // triggering the call (for now it's trough 'adb shell cmd autofill request' + if (activityToken == null) { + // Let's get top activities from all visible stacks. + + // TODO: overload getTopVisibleActivities() to take userId, otherwise it could return + // activities for different users when a work profile app is displayed in another + // window (in a multi-window environment). + final List<IBinder> topActivities = LocalServices + .getService(ActivityManagerInternal.class).getTopVisibleActivities(); + if (DEBUG) + Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities); + if (topActivities.isEmpty()) { + Slog.w(TAG, "Could not get top activity"); + return; + } + activityToken = topActivities.get(0); + } + + final String historyItem = + DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken; + synchronized (mLock) { + mRequestHistory.add(historyItem); + requestAutoFillLocked(activityToken, true); + } + } + + private void requestAutoFillLocked(IBinder activityToken, boolean queueIfNecessary) { + if (mService == null) { + if (!queueIfNecessary) { + Slog.w(TAG, "requestAutoFillLocked(): service is null"); + return; + } + if (DEBUG) Slog.d(TAG, "requestAutoFill(): service not set yet, queuing it"); + mQueuedRequests.add(activityToken); + return; + } + + /* + * TODO: apply security checks below: + * - checks if disabled by secure settings / device policy + * - log operation using noteOp() + * - check flags + * - display disclosure if needed + */ + try { + // TODO: add MetricsLogger call + if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken)) { + // TODO: might need a way to warn user (perhaps a new method on AutoFillService). + Slog.w(TAG, "failed to request auto-fill data for " + activityToken); + } + } catch (RemoteException e) { + // Should happen, it's a local call. + } + } + + void stopLocked() { + if (DEBUG) Slog.d(TAG, "stopLocked()"); + + // Sanity check. + if (mService == null) { + Log.w(TAG, "service already null on shutdown"); + return; + } + try { + mService.onDisconnected(); + } catch (RemoteException e) { + if (! (e instanceof DeadObjectException)) { + Slog.w(TAG, "Exception calling service.onDisconnected(): " + e); + } + } finally { + mService = null; + } + + if (mBound) { + mContext.unbindService(mConnection); + mBound = false; + } + if (mValid) { + mContext.unregisterReceiver(mBroadcastReceiver); + } + } + + void dumpLocked(String prefix, PrintWriter pw) { + if (!mValid) { + pw.print(" NOT VALID: "); + if (mInfo == null) { + pw.println("no info"); + } else { + pw.println(mInfo.getParseError()); + } + return; + } + + pw.print(prefix); pw.print("mUserId="); pw.println(mUserId); + pw.print(prefix); pw.print("mUid="); pw.println(mUid); + pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString()); + pw.print(prefix); pw.print("mBound="); pw.println(mBound); + pw.print(prefix); pw.print("mService="); pw.println(mService); + pw.print(prefix); pw.print("mEstimateTimeOfDeath="); + TimeUtils.formatDuration(mEstimateTimeOfDeath, SystemClock.uptimeMillis(), pw); + pw.println(); + + if (DEBUG) { + // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps) + pw.print(prefix); pw.println("Service info:"); + mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix); + } + + if (mRequestHistory.isEmpty()) { + pw.print(prefix); pw.println("No history"); + } else { + pw.print(prefix); pw.println("History:"); + final String prefix2 = prefix + prefix; + for (int i = 0; i < mRequestHistory.size(); i++) { + pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mRequestHistory.get(i)); + } + } + if (mQueuedRequests.isEmpty()) { + pw.print(prefix); pw.println("No queued requests"); + } else { + pw.print(prefix); pw.println("Queued requests:"); + final String prefix2 = prefix + prefix; + for (int i = 0; i < mQueuedRequests.size(); i++) { + pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mQueuedRequests.get(i)); + } + } + } + + @Override + public String toString() { + return "[AutoFillManagerServiceImpl: userId=" + mUserId + ", uid=" + mUid + + ", component=" + mComponent.flattenToShortString() + "]"; + } +} diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java new file mode 100644 index 000000000000..6406b8ac9a31 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java @@ -0,0 +1,79 @@ +/* + * 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.autofill; + +import android.app.ActivityManager; +import android.os.RemoteException; +import android.os.ShellCommand; +import android.os.UserHandle; +import android.service.autofill.IAutoFillManagerService; + +import java.io.PrintWriter; + +public final class AutoFillManagerServiceShellCommand extends ShellCommand { + + private final IAutoFillManagerService.Stub mService; + + public AutoFillManagerServiceShellCommand(IAutoFillManagerService.Stub service) { + mService = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + final PrintWriter pw = getOutPrintWriter(); + try { + switch (cmd) { + case "request": + return requestAutoFill(); + default: + return handleDefaultCommands(cmd); + } + } catch (RemoteException e) { + pw.println("error: " + e); + } + return -1; + } + + @Override + public void onHelp() { + try (final PrintWriter pw = getOutPrintWriter();) { + pw.println("AutoFill Service (autofill) commands:"); + pw.println(" help"); + pw.println(" Prints this help text."); + pw.println(""); + pw.println(" request [--user USER_ID]"); + pw.println(" Request auto-fill on the top activity. "); + pw.println(""); + } + } + + private int requestAutoFill() throws RemoteException { + final int userId = getUserIdFromArgs(); + mService.requestAutoFill(userId, null); + return 0; + } + + private int getUserIdFromArgs() { + if ("--user".equals(getNextArg())) { + return UserHandle.parseUserArg(getNextArgRequired()); + } + return ActivityManager.getCurrentUser(); + } +} diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 6375e9a39dae..8151c8aa1e88 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -18,7 +18,7 @@ package com.android.server.backup; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.ApplicationThreadConstants; @@ -80,7 +80,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.WorkSource; import android.os.Environment.UserEnvironment; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.Settings; import android.system.ErrnoException; @@ -268,7 +268,7 @@ public class BackupManagerService { private IActivityManager mActivityManager; private PowerManager mPowerManager; private AlarmManager mAlarmManager; - private IMountService mMountService; + private IStorageManager mStorageManager; IBackupManager mBackupManagerBinder; boolean mEnabled; // access to this is synchronized on 'this' @@ -1075,11 +1075,11 @@ public class BackupManagerService { mContext = context; mPackageManager = context.getPackageManager(); mPackageManagerBinder = AppGlobals.getPackageManager(); - mActivityManager = ActivityManagerNative.getDefault(); + mActivityManager = ActivityManager.getService(); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); + mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); @@ -3982,14 +3982,14 @@ public class BackupManagerService { boolean deviceIsEncrypted() { try { - return mMountService.getEncryptionState() + return mStorageManager.getEncryptionState() != StorageManager.ENCRYPTION_STATE_NONE - && mMountService.getPasswordType() + && mStorageManager.getPasswordType() != StorageManager.CRYPT_TYPE_DEFAULT; } catch (Exception e) { - // If we can't talk to the mount service we have a serious problem; fail + // If we can't talk to the storagemanager service we have a serious problem; fail // "secure" i.e. assuming that the device is encrypted. - Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage()); + Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage()); return true; } } diff --git a/services/core/Android.mk b/services/core/Android.mk index 11586eedfee4..88a83855bbb0 100644 --- a/services/core/Android.mk +++ b/services/core/Android.mk @@ -19,8 +19,9 @@ LOCAL_AIDL_INCLUDES += \ LOCAL_JAVA_LIBRARIES := \ services.net \ telephony-common \ + android.hardware.light@2.0-java \ android.hardware.power@1.0-java \ - android.hardware.light@2.0-java + android.hardware.tv.cec@1.0-java LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 8e01e9eae376..581aa05d7d32 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -18,7 +18,6 @@ package com.android.server; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; @@ -505,7 +504,7 @@ class AlarmManagerService extends SystemService { for (int i = alarms.size()-1; i >= 0; i--) { Alarm alarm = alarms.get(i); try { - if (alarm.uid == uid && ActivityManagerNative.getDefault().getAppStartMode( + if (alarm.uid == uid && ActivityManager.getService().getAppStartMode( uid, alarm.packageName) == ActivityManager.APP_START_MODE_DISABLED) { alarms.remove(i); didRemove = true; @@ -937,8 +936,8 @@ class AlarmManagerService extends SystemService { } try { - ActivityManagerNative.getDefault().registerUidObserver(new UidObserver(), - ActivityManager.UID_OBSERVER_IDLE, null); + ActivityManager.getService().registerUidObserver(new UidObserver(), + ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN, null); } catch (RemoteException e) { // ignored; both services live in system_server } @@ -1090,7 +1089,7 @@ class AlarmManagerService extends SystemService { operation, directReceiver, listenerTag, workSource, flags, alarmClock, callingUid, callingPackage); try { - if (ActivityManagerNative.getDefault().getAppStartMode(callingUid, callingPackage) + if (ActivityManager.getService().getAppStartMode(callingUid, callingPackage) == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a + " -- package not allowed to start"); @@ -1940,13 +1939,9 @@ class AlarmManagerService extends SystemService { } for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) { final Alarm a = mPendingWhileIdleAlarms.get(i); - try { - if (a.uid == uid && ActivityManagerNative.getDefault().getAppStartMode( - uid, a.packageName) == ActivityManager.APP_START_MODE_DISABLED) { - // Don't set didRemove, since this doesn't impact the scheduled alarms. - mPendingWhileIdleAlarms.remove(i); - } - } catch (RemoteException e) { + if (a.uid == uid) { + // Don't set didRemove, since this doesn't impact the scheduled alarms. + mPendingWhileIdleAlarms.remove(i); } } @@ -2418,11 +2413,11 @@ class AlarmManagerService extends SystemService { if (RECORD_ALARMS_IN_HISTORY) { if (alarm.workSource != null && alarm.workSource.size() > 0) { for (int wi=0; wi<alarm.workSource.size(); wi++) { - ActivityManagerNative.noteAlarmStart( + ActivityManager.noteAlarmStart( alarm.operation, alarm.workSource.get(wi), alarm.statsTag); } } else { - ActivityManagerNative.noteAlarmStart( + ActivityManager.noteAlarmStart( alarm.operation, alarm.uid, alarm.statsTag); } } @@ -2586,7 +2581,7 @@ class AlarmManagerService extends SystemService { final int uid = (knownUid >= 0) ? knownUid - : ActivityManagerNative.getDefault().getUidForIntentSender(pi.getTarget()); + : ActivityManager.getService().getUidForIntentSender(pi.getTarget()); if (uid >= 0) { mWakeLock.setWorkSource(new WorkSource(uid)); return; @@ -2807,15 +2802,22 @@ class AlarmManagerService extends SystemService { @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { } - @Override public void onUidGone(int uid) throws RemoteException { + @Override public void onUidGone(int uid, boolean disabled) throws RemoteException { + if (disabled) { + synchronized (mLock) { + removeForStoppedLocked(uid); + } + } } @Override public void onUidActive(int uid) throws RemoteException { } - @Override public void onUidIdle(int uid) throws RemoteException { - synchronized (mLock) { - removeForStoppedLocked(uid); + @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException { + if (disabled) { + synchronized (mLock) { + removeForStoppedLocked(uid); + } } } }; @@ -2878,11 +2880,11 @@ class AlarmManagerService extends SystemService { if (RECORD_ALARMS_IN_HISTORY) { if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) { for (int wi=0; wi<inflight.mWorkSource.size(); wi++) { - ActivityManagerNative.noteAlarmFinish( + ActivityManager.noteAlarmFinish( inflight.mPendingIntent, inflight.mWorkSource.get(wi), inflight.mTag); } } else { - ActivityManagerNative.noteAlarmFinish( + ActivityManager.noteAlarmFinish( inflight.mPendingIntent, inflight.mUid, inflight.mTag); } } @@ -3083,13 +3085,13 @@ class AlarmManagerService extends SystemService { if (alarm.workSource != null && alarm.workSource.size() > 0) { for (int wi=0; wi<alarm.workSource.size(); wi++) { final String wsName = alarm.workSource.getName(wi); - ActivityManagerNative.noteWakeupAlarm( + ActivityManager.noteWakeupAlarm( alarm.operation, alarm.workSource.get(wi), (wsName != null) ? wsName : alarm.packageName, alarm.statsTag); } } else { - ActivityManagerNative.noteWakeupAlarm( + ActivityManager.noteWakeupAlarm( alarm.operation, alarm.uid, alarm.packageName, alarm.statsTag); } } diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 7c2eea3f68aa..570843e3064b 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -54,7 +54,7 @@ import android.os.ServiceManager; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.UserHandle; -import android.os.storage.MountServiceInternal; +import android.os.storage.StorageManagerInternal; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -294,10 +294,10 @@ public class AppOpsService extends IAppOpsService.Stub { } } - MountServiceInternal mountServiceInternal = LocalServices.getService( - MountServiceInternal.class); - mountServiceInternal.addExternalStoragePolicy( - new MountServiceInternal.ExternalStorageMountPolicy() { + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + storageManagerInternal.addExternalStoragePolicy( + new StorageManagerInternal.ExternalStorageMountPolicy() { @Override public int getMountMode(int uid, String packageName) { if (Process.isIsolated(uid)) { diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index b88a45edee1b..573ad631891e 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -28,7 +28,7 @@ import com.android.server.am.BatteryStatsService; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -557,7 +557,7 @@ public final class BatteryService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); + ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); } }); } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 645604848580..f7068cf3fb4b 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -59,6 +59,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.concurrent.ConcurrentHashMap; import java.util.HashMap; import java.util.Map; @@ -118,7 +119,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int SERVICE_IBLUETOOTHGATT = 2; private final Context mContext; - private static int mBleAppCount = 0; // Locks are not provided for mName and mAddress. // They are accessed in handler or broadcast receiver, same thread context. @@ -212,10 +212,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (isAirplaneModeOn()) { // Clear registered LE apps to force shut-off - synchronized (this) { - mBleAppCount = 0; - mBleApps.clear(); - } + clearBleApps(); if (st == BluetoothAdapter.STATE_BLE_ON) { //if state is BLE_ON make sure you trigger disableBLE part try { @@ -460,28 +457,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { class ClientDeathRecipient implements IBinder.DeathRecipient { public void binderDied() { if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App"); - if (mBleAppCount > 0) --mBleAppCount; - - if (mBleAppCount == 0) { - if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash"); - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null && - mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) { - mEnable = false; - mBluetooth.onBrEdrDown(); - } - } catch (RemoteException e) { - Slog.e(TAG,"Unable to call onBrEdrDown", e); - } finally { - mBluetoothLock.readLock().unlock(); + if (isBleAppPresent()) { + // Nothing to do, another app is here. + return; + } + if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash"); + try { + mBluetoothLock.readLock().lock(); + if (mBluetooth != null && + mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) { + mEnable = false; + mBluetooth.onBrEdrDown(); } + } catch (RemoteException e) { + Slog.e(TAG,"Unable to call onBrEdrDown", e); + } finally { + mBluetoothLock.readLock().unlock(); } } } /** Internal death rec list */ - Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>(); + Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); @Override public boolean isBleScanAlwaysAvailable() { @@ -501,17 +498,20 @@ class BluetoothManagerService extends IBluetoothManager.Stub { ContentObserver contentObserver = new ContentObserver(null) { @Override public void onChange(boolean selfChange) { - if (!isBleScanAlwaysAvailable()) { - disableBleScanMode(); - clearBleApps(); - try { - mBluetoothLock.readLock().lock(); - if (mBluetooth != null) mBluetooth.onBrEdrDown(); - } catch (RemoteException e) { - Slog.e(TAG, "error when disabling bluetooth", e); - } finally { - mBluetoothLock.readLock().unlock(); - } + if (isBleScanAlwaysAvailable()) { + // Nothing to do + return; + } + // BLE scan is not available. + disableBleScanMode(); + clearBleApps(); + try { + mBluetoothLock.readLock().lock(); + if (mBluetooth != null) mBluetooth.onBrEdrDown(); + } catch (RemoteException e) { + Slog.e(TAG, "error when disabling bluetooth", e); + } finally { + mBluetoothLock.readLock().unlock(); } } }; @@ -547,9 +547,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { throw new IllegalArgumentException("Wake lock is already dead."); } mBleApps.put(token, deathRec); - synchronized (this) { - ++mBleAppCount; - } if (DBG) Slog.d(TAG, "Registered for death Notification"); } @@ -559,31 +556,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // Unregister death recipient as the app goes away. token.unlinkToDeath(r, 0); mBleApps.remove(token); - synchronized (this) { - if (mBleAppCount > 0) --mBleAppCount; - } if (DBG) Slog.d(TAG, "Unregistered for death Notification"); } } - if (DBG) Slog.d(TAG, "Updated BleAppCount" + mBleAppCount); - if (mBleAppCount == 0 && mEnable) { + int appCount = mBleApps.size(); + if (DBG) Slog.d(TAG, appCount + " registered Ble Apps"); + if (appCount == 0 && mEnable) { disableBleScanMode(); } - return mBleAppCount; + return appCount; } // Clear all apps using BLE scan only mode. private void clearBleApps() { - synchronized (this) { - mBleApps.clear(); - mBleAppCount = 0; - } + mBleApps.clear(); } /** @hide*/ public boolean isBleAppPresent() { - if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleAppCount); - return (mBleAppCount > 0); + if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size()); + return mBleApps.size() > 0; } /** @@ -1364,7 +1356,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.writeLock().lock(); if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { - mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); + mBluetoothGatt = IBluetoothGatt.Stub + .asInterface(Binder.allowBlocking(service)); onBluetoothGattServiceUp(); break; } // else must be SERVICE_IBLUETOOTH @@ -1374,7 +1367,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBinding = false; mBluetoothBinder = service; - mBluetooth = IBluetooth.Stub.asInterface(service); + mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service)); if (!isNameAndAddressSet()) { Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); @@ -1448,12 +1441,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) { - recoverBluetoothServiceFromError(); + recoverBluetoothServiceFromError(false); } if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) { - recoverBluetoothServiceFromError(); + recoverBluetoothServiceFromError(true); } // If we tried to enable BT while BT was in the process of shutting down, // wait for the BT process to fully tear down and then force a restart @@ -1869,7 +1862,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { quietMode ? 1 : 0, 0)); } - private void recoverBluetoothServiceFromError() { + private void recoverBluetoothServiceFromError(boolean clearBle) { Slog.e(TAG,"recoverBluetoothServiceFromError"); try { mBluetoothLock.readLock().lock(); @@ -1907,6 +1900,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); mState = BluetoothAdapter.STATE_OFF; + if (clearBle) { + clearBleApps(); + } + mEnable = false; if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index de700266e4c2..5eceb9f1395b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5342,6 +5342,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // notify only this one new request of the current state protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) { int notifyType = ConnectivityManager.CALLBACK_AVAILABLE; + mHandler.removeMessages(EVENT_TIMEOUT_NETWORK_REQUEST, nri); if (nri.mPendingIntent == null) { callCallbackForRequest(nri, nai, notifyType, 0); } else { diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 466633a05e4e..07322fcbf915 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -17,7 +17,7 @@ package com.android.server; import android.Manifest; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -1572,7 +1572,7 @@ public class DeviceIdleController extends SystemService Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, "No permission to change device idle whitelist"); final int callingUid = Binder.getCallingUid(); - userId = ActivityManagerNative.getDefault().handleIncomingUser( + userId = ActivityManager.getService().handleIncomingUser( Binder.getCallingPid(), callingUid, userId, diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 74ff41c13802..eb2cd0b3ae4b 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -248,7 +248,7 @@ option java_package com.android.server 51501 idle_maintenance_window_finish (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5) # --------------------------- -# MountService.java +# StorageManagerService.java # --------------------------- 2755 fstrim_start (time|2|3) 2756 fstrim_finish (time|2|3) diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index 553cb071613b..830a6ed23f9c 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -40,7 +40,7 @@ import android.util.Slog; import android.view.KeyEvent; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.statusbar.StatusBarManagerInternal; /** diff --git a/services/core/java/com/android/server/InputContentUriTokenHandler.java b/services/core/java/com/android/server/InputContentUriTokenHandler.java index 3f4972babf6e..57cdc9456b7b 100644 --- a/services/core/java/com/android/server/InputContentUriTokenHandler.java +++ b/services/core/java/com/android/server/InputContentUriTokenHandler.java @@ -18,7 +18,7 @@ package com.android.server; import android.annotation.NonNull; import android.annotation.UserIdInt; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.Intent; import android.net.Uri; import android.os.Binder; @@ -64,7 +64,7 @@ final class InputContentUriTokenHandler extends IInputContentUriToken.Stub { } try { - mPermissionOwnerToken = ActivityManagerNative.getDefault() + mPermissionOwnerToken = ActivityManager.getService() .newUriPermissionOwner("InputContentUriTokenHandler"); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -78,7 +78,7 @@ final class InputContentUriTokenHandler extends IInputContentUriToken.Stub { long origId = Binder.clearCallingIdentity(); try { try { - ActivityManagerNative.getDefault().grantUriPermissionFromOwner( + ActivityManager.getService().grantUriPermissionFromOwner( permissionOwner, mSourceUid, mTargetPackage, mUri, Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId, mTargetUserId); } catch (RemoteException e) { @@ -96,7 +96,7 @@ final class InputContentUriTokenHandler extends IInputContentUriToken.Stub { return; } try { - ActivityManagerNative.getDefault().revokeUriPermissionFromOwner( + ActivityManager.getService().revokeUriPermissionFromOwner( mPermissionOwnerToken, mUri, Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 2698f9546357..3dfbdc392b13 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -29,6 +29,7 @@ import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; +import com.android.internal.os.TransferPipe; import com.android.internal.util.FastXmlSerializer; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethod; @@ -48,8 +49,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AlertDialog; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -59,6 +60,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; @@ -905,7 +907,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mNotificationShown = false; int userId = 0; try { - userId = ActivityManagerNative.getDefault().getCurrentUser().id; + userId = ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e); } @@ -3968,10 +3970,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + mCurAttribute.packageName + " packageName=" + packageName); return null; } + // This user ID can never bee spoofed. final int imeUserId = UserHandle.getUserId(uid); + // This user ID can never bee spoofed. final int appUserId = UserHandle.getUserId(mCurClient.uid); - return new InputContentUriTokenHandler(contentUri, uid, packageName, imeUserId, - appUserId); + // This user ID may be invalid if "contentUri" embedded an invalid user ID. + final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri, + imeUserId); + final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri); + // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid") + // actually has the right to grant a read permission for "contentUriWithoutUserId" that + // is claimed to belong to "contentUriOwnerUserId". For example, specifying random + // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown + // from InputContentUriTokenHandler.take() and can never be allowed beyond what is + // actually allowed to "uid", which is guaranteed to be the IME's one. + return new InputContentUriTokenHandler(contentUriWithoutUserId, uid, + packageName, contentUriOwnerUserId, appUserId); } } @@ -4041,9 +4055,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (client != null) { pw.flush(); try { - client.client.asBinder().dump(fd, args); - } catch (RemoteException e) { - p.println("Input method client dead: " + e); + TransferPipe.dumpAsync(client.client.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + p.println("Failed to dump input method client: " + e); } } else { p.println("No input method client."); @@ -4057,9 +4071,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" "); pw.flush(); try { - focusedWindowClient.client.asBinder().dump(fd, args); - } catch (RemoteException e) { - p.println("Input method client in focused window dead: " + e); + TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + p.println("Failed to dump input method client in focused window: " + e); } } @@ -4067,9 +4081,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (method != null) { pw.flush(); try { - method.asBinder().dump(fd, args); - } catch (RemoteException e) { - p.println("Input method service dead: " + e); + TransferPipe.dumpAsync(method.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + p.println("Failed to dump input method service: " + e); } } else { p.println("No input method service."); diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index a2207b259123..67014314595f 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -16,7 +16,7 @@ package com.android.server; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationManager; @@ -49,7 +49,9 @@ import android.os.IProgressListener; import android.os.Parcel; import android.os.Process; import android.os.RemoteException; -import android.os.storage.IMountService; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.os.ServiceManager; import android.os.StrictMode; @@ -79,6 +81,7 @@ import com.android.server.LockSettingsStorage.CredentialHash; import libcore.util.HexEncoding; import java.io.ByteArrayOutputStream; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -810,7 +813,7 @@ public class LockSettingsService extends ILockSettings.Stub { }; try { - ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener); + ActivityManager.getService().unlockUser(userId, token, secret, listener); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -1157,10 +1160,10 @@ public class LockSettingsService extends ILockSettings.Stub { private void addUserKeyAuth(int userId, byte[] token, byte[] secret) throws RemoteException { final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId); - final IMountService mountService = getMountService(); + final IStorageManager storageManager = getStorageManager(); final long callingId = Binder.clearCallingIdentity(); try { - mountService.addUserKeyAuth(userId, userInfo.serialNumber, token, secret); + storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret); } finally { Binder.restoreCallingIdentity(callingId); } @@ -1168,10 +1171,10 @@ public class LockSettingsService extends ILockSettings.Stub { private void fixateNewestUserKeyAuth(int userId) throws RemoteException { - final IMountService mountService = getMountService(); + final IStorageManager storageManager = getStorageManager(); final long callingId = Binder.clearCallingIdentity(); try { - mountService.fixateNewestUserKeyAuth(userId); + storageManager.fixateNewestUserKeyAuth(userId); } finally { Binder.restoreCallingIdentity(callingId); } @@ -1485,7 +1488,7 @@ public class LockSettingsService extends ILockSettings.Stub { // we should, within the first minute of decrypting the phone if this // service can't connect to vold, it restarts, and then the new instance // does successfully connect. - final IMountService service = getMountService(); + final IStorageManager service = getStorageManager(); String password; long identity = Binder.clearCallingIdentity(); try { @@ -1585,6 +1588,31 @@ public class LockSettingsService extends ILockSettings.Stub { return mStrongAuthTracker.getStrongAuthForUser(userId); } + private boolean isCallerShell() { + final int callingUid = Binder.getCallingUid(); + return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID; + } + + private void enforceShell() { + if (!isCallerShell()) { + throw new SecurityException("Caller must be shell"); + } + } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver resultReceiver) + throws RemoteException { + enforceShell(); + final long origId = Binder.clearCallingIdentity(); + try { + (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec( + this, in, out, err, args, callback, resultReceiver); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + private static final String[] VALID_SETTINGS = new String[] { LockPatternUtils.LOCKOUT_PERMANENT_KEY, LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, @@ -1623,10 +1651,10 @@ public class LockSettingsService extends ILockSettings.Stub { Secure.LOCK_SCREEN_OWNER_INFO }; - private IMountService getMountService() { + private IStorageManager getStorageManager() { final IBinder service = ServiceManager.getService("mount"); if (service != null) { - return IMountService.Stub.asInterface(service); + return IStorageManager.Stub.asInterface(service); } return null; } diff --git a/services/core/java/com/android/server/LockSettingsShellCommand.java b/services/core/java/com/android/server/LockSettingsShellCommand.java new file mode 100644 index 000000000000..f72663aed140 --- /dev/null +++ b/services/core/java/com/android/server/LockSettingsShellCommand.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server; + +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; +import static com.android.internal.widget.LockPatternUtils.stringToPattern; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Binder; +import android.os.Process; +import android.os.RemoteException; +import android.os.ShellCommand; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternUtils.RequestThrottledException; + +class LockSettingsShellCommand extends ShellCommand { + + private static final String COMMAND_SET_PATTERN = "set-pattern"; + private static final String COMMAND_SET_PIN = "set-pin"; + private static final String COMMAND_SET_PASSWORD = "set-password"; + private static final String COMMAND_CLEAR = "clear"; + + private int mCurrentUserId; + private final LockPatternUtils mLockPatternUtils; + private final Context mContext; + private String mOld = ""; + private String mNew = ""; + + LockSettingsShellCommand(Context context, LockPatternUtils lockPatternUtils) { + mContext = context; + mLockPatternUtils = lockPatternUtils; + } + + @Override + public int onCommand(String cmd) { + try { + mCurrentUserId = ActivityManager.getService().getCurrentUser().id; + + parseArgs(); + if (!checkCredential()) { + return -1; + } + switch (cmd) { + case COMMAND_SET_PATTERN: + runSetPattern(); + break; + case COMMAND_SET_PASSWORD: + runSetPassword(); + break; + case COMMAND_SET_PIN: + runSetPin(); + break; + case COMMAND_CLEAR: + runClear(); + break; + default: + getErrPrintWriter().println("Unknown command: " + cmd); + break; + } + return 0; + } catch (Exception e) { + getErrPrintWriter().println("Error while executing command: " + e); + return -1; + } + } + + @Override + public void onHelp() { + } + + private void parseArgs() { + String opt; + while ((opt = getNextOption()) != null) { + if ("--old".equals(opt)) { + mOld = getNextArgRequired(); + } else { + getErrPrintWriter().println("Unknown option: " + opt); + throw new IllegalArgumentException(); + } + } + mNew = getNextArg(); + } + + private void runSetPattern() throws RemoteException { + mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId); + getOutPrintWriter().println("Pattern set to '" + mNew + "'"); + } + + private void runSetPassword() throws RemoteException { + mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId); + getOutPrintWriter().println("Password set to '" + mNew + "'"); + } + + private void runSetPin() throws RemoteException { + mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId); + getOutPrintWriter().println("Pin set to '" + mNew + "'"); + } + + private void runClear() throws RemoteException { + mLockPatternUtils.clearLock(mCurrentUserId); + getOutPrintWriter().println("Lock credential cleared"); + } + + private boolean checkCredential() throws RemoteException, RequestThrottledException { + final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId); + final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId); + if (havePassword || havePattern) { + boolean result; + if (havePassword) { + result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId); + } else { + result = mLockPatternUtils.checkPattern(stringToPattern(mOld), + mCurrentUserId); + } + if (result) { + return true; + } else { + getOutPrintWriter().println("Old password '" + mOld + "' didn't match"); + return false; + } + } else { + return true; + } + } +} diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index 33f92344f615..0414b47e0604 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -92,7 +92,7 @@ public class MmsServiceBroker extends SystemService { public void onServiceConnected(ComponentName name, IBinder service) { Slog.i(TAG, "MmsService connected"); synchronized (MmsServiceBroker.this) { - mService = IMms.Stub.asInterface(service); + mService = IMms.Stub.asInterface(Binder.allowBlocking(service)); MmsServiceBroker.this.notifyAll(); } } diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index e0b2307e89f3..d8bd0bb5a93c 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -18,7 +18,7 @@ package com.android.server; import java.util.Calendar; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; @@ -59,7 +59,7 @@ public class MountServiceIdler extends JobService { // is really more than just mount, some day it should be renamed to be system // idleer). try { - ActivityManagerNative.getDefault().performIdleMaintenance(); + ActivityManager.getService().performIdleMaintenance(); } catch (RemoteException e) { } // The mount service will run an fstrim operation asynchronously @@ -67,7 +67,7 @@ public class MountServiceIdler extends JobService { // that lets us cleanly end our idle timeslice. It's safe to call // finishIdle() from any thread. mJobParams = params; - MountService ms = MountService.sSelf; + StorageManagerService ms = StorageManagerService.sSelf; if (ms != null) { synchronized (mFinishCallback) { mStarted = true; diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index e64aa160b2e2..5654096e1c91 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -46,7 +46,7 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult; import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; import android.annotation.NonNull; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.net.ConnectivityManager; @@ -958,7 +958,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub final int uid = Integer.parseInt(cooked[1]); final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]); try { - ActivityManagerNative.getDefault().notifyCleartextNetwork(uid, firstPacket); + ActivityManager.getService().notifyCleartextNetwork(uid, firstPacket); } catch (RemoteException ignored) { } break; diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index 83d6344c95b0..f5cda0ab4d63 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -42,8 +42,10 @@ import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; +import com.android.internal.os.TransferPipe; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; @@ -418,12 +420,9 @@ public class NetworkScoreService extends INetworkScoreService.Stub { for (INetworkScoreCache scoreCache : getScoreCaches()) { try { - scoreCache.asBinder().dump(fd, args); - } catch (RemoteException e) { - writer.println("Unable to dump score cache"); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Unable to dump score cache", e); - } + TransferPipe.dumpAsync(scoreCache.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + writer.println("Failed to dump score cache: " + e); } } if (mServiceConnection != null) { diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 356ccb3596a9..fa5a52c712cd 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -63,7 +63,7 @@ public final class PinnerService extends SystemService { private BinderService mBinderService; - private final long MAX_CAMERA_PIN_SIZE = 50 * (1 << 20); //50MB max + private final long MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max private PinnerHandler mPinnerHandler = null; @@ -192,6 +192,9 @@ public final class PinnerService extends SystemService { if (isResolverActivity(cameraResolveInfo.activityInfo)) { + if (DEBUG) { + Slog.v(TAG, "cameraIntent returned resolverActivity"); + } return null; } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/StorageManagerService.java index 8b7b6a0f8016..11fabb4182ff 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -31,7 +31,6 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.IActivityManager; import android.content.BroadcastReceiver; @@ -69,11 +68,11 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.DiskInfo; -import android.os.storage.IMountService; -import android.os.storage.IMountServiceListener; -import android.os.storage.IMountShutdownObserver; +import android.os.storage.IStorageEventListener; +import android.os.storage.IStorageShutdownObserver; import android.os.storage.IObbActionListener; -import android.os.storage.MountServiceInternal; +import android.os.storage.IStorageManager; +import android.os.storage.StorageManagerInternal; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; @@ -150,14 +149,14 @@ import javax.crypto.spec.PBEKeySpec; * watch for and manage dynamically added storage, such as SD cards and USB mass * storage. Also decides how storage should be presented to users on the device. */ -class MountService extends IMountService.Stub +class StorageManagerService extends IStorageManager.Stub implements INativeDaemonConnectorCallbacks, Watchdog.Monitor { // Static direct instance pointer for the tightly-coupled idle service to use - static MountService sSelf = null; + static StorageManagerService sSelf = null; public static class Lifecycle extends SystemService { - private MountService mMountService; + private StorageManagerService mStorageManagerService; public Lifecycle(Context context) { super(context); @@ -165,33 +164,33 @@ class MountService extends IMountService.Stub @Override public void onStart() { - mMountService = new MountService(getContext()); - publishBinderService("mount", mMountService); - mMountService.start(); + mStorageManagerService = new StorageManagerService(getContext()); + publishBinderService("mount", mStorageManagerService); + mStorageManagerService.start(); } @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { - mMountService.systemReady(); + mStorageManagerService.systemReady(); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { - mMountService.bootCompleted(); + mStorageManagerService.bootCompleted(); } } @Override public void onSwitchUser(int userHandle) { - mMountService.mCurrentUserId = userHandle; + mStorageManagerService.mCurrentUserId = userHandle; } @Override public void onUnlockUser(int userHandle) { - mMountService.onUnlockUser(userHandle); + mStorageManagerService.onUnlockUser(userHandle); } @Override public void onCleanupUser(int userHandle) { - mMountService.onCleanupUser(userHandle); + mStorageManagerService.onCleanupUser(userHandle); } } @@ -210,7 +209,7 @@ class MountService extends IMountService.Stub */ private static final boolean EMULATE_FBE_SUPPORTED = true; - private static final String TAG = "MountService"; + private static final String TAG = "StorageManagerService"; private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark"; private static final String TAG_STORAGE_TRIM = "storage_trim"; @@ -501,7 +500,8 @@ class MountService extends IMountService.Stub final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); // Not guarded by a lock. - private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl(); + private final StorageManagerInternalImpl mStorageManagerInternal + = new StorageManagerInternalImpl(); class ObbState implements IBinder.DeathRecipient { public ObbState(String rawPath, String canonicalPath, int callingUid, @@ -610,8 +610,8 @@ class MountService extends IMountService.Stub private static final int H_PARTITION_FORGET = 9; private static final int H_RESET = 10; - class MountServiceHandler extends Handler { - public MountServiceHandler(Looper looper) { + class StorageManagerServiceHandler extends Handler { + public StorageManagerServiceHandler(Looper looper) { super(looper); } @@ -662,7 +662,7 @@ class MountService extends IMountService.Stub break; } case H_SHUTDOWN: { - final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj; + final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj; boolean success = false; try { success = mConnector.execute("volume", "shutdown").isClassOk(); @@ -836,7 +836,7 @@ class MountService extends IMountService.Stub | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, user.id); if (provider != null) { - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); try { am.killApplication(provider.applicationInfo.packageName, UserHandle.getAppId(provider.applicationInfo.uid), @@ -1029,7 +1029,7 @@ class MountService extends IMountService.Stub Configuration config = new Configuration(); config.setLocale(locale); try { - ActivityManagerNative.getDefault().updatePersistentConfiguration(config); + ActivityManager.getService().updatePersistentConfiguration(config); } catch (RemoteException e) { Slog.e(TAG, "Error setting system locale from mount service", e); } @@ -1482,11 +1482,11 @@ class MountService extends IMountService.Stub } /** - * Constructs a new MountService instance + * Constructs a new StorageManagerService instance * * @param context Binder context for this service */ - public MountService(Context context) { + public StorageManagerService(Context context) { sSelf = this; mContext = context; @@ -1498,9 +1498,9 @@ class MountService extends IMountService.Stub HandlerThread hthread = new HandlerThread(TAG); hthread.start(); - mHandler = new MountServiceHandler(hthread.getLooper()); + mHandler = new StorageManagerServiceHandler(hthread.getLooper()); - // Add OBB Action Handler to MountService thread. + // Add OBB Action Handler to StorageManagerService thread. mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper()); // Initialize the last-fstrim tracking if necessary @@ -1526,7 +1526,7 @@ class MountService extends IMountService.Stub readSettingsLocked(); } - LocalServices.addService(MountServiceInternal.class, mMountServiceInternal); + LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal); /* * Create the connection to vold with a maximum queue of twice the @@ -1686,17 +1686,17 @@ class MountService extends IMountService.Stub */ @Override - public void registerListener(IMountServiceListener listener) { + public void registerListener(IStorageEventListener listener) { mCallbacks.register(listener); } @Override - public void unregisterListener(IMountServiceListener listener) { + public void unregisterListener(IStorageEventListener listener) { mCallbacks.unregister(listener); } @Override - public void shutdown(final IMountShutdownObserver observer) { + public void shutdown(final IStorageShutdownObserver observer) { enforcePermission(android.Manifest.permission.SHUTDOWN); Slog.i(TAG, "Shutting down"); @@ -3046,7 +3046,7 @@ class MountService extends IMountService.Stub final long token = Binder.clearCallingIdentity(); try { userKeyUnlocked = isUserKeyUnlocked(userId); - storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName); + storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName); } finally { Binder.restoreCallingIdentity(token); } @@ -3163,7 +3163,7 @@ class MountService extends IMountService.Stub for (final ObbState o : obbStates) { if (o.rawPath.equals(obbState.rawPath)) { throw new IllegalStateException("Attempt to add ObbState twice. " - + "This indicates an error in the MountService logic."); + + "This indicates an error in the StorageManagerService logic."); } } } @@ -3425,7 +3425,7 @@ class MountService extends IMountService.Stub try { mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status); } catch (RemoteException e) { - Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); + Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged"); } } } @@ -3615,18 +3615,18 @@ class MountService extends IMountService.Stub private static final int MSG_DISK_SCANNED = 5; private static final int MSG_DISK_DESTROYED = 6; - private final RemoteCallbackList<IMountServiceListener> + private final RemoteCallbackList<IStorageEventListener> mCallbacks = new RemoteCallbackList<>(); public Callbacks(Looper looper) { super(looper); } - public void register(IMountServiceListener callback) { + public void register(IStorageEventListener callback) { mCallbacks.register(callback); } - public void unregister(IMountServiceListener callback) { + public void unregister(IStorageEventListener callback) { mCallbacks.unregister(callback); } @@ -3635,7 +3635,7 @@ class MountService extends IMountService.Stub final SomeArgs args = (SomeArgs) msg.obj; final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { - final IMountServiceListener callback = mCallbacks.getBroadcastItem(i); + final IStorageEventListener callback = mCallbacks.getBroadcastItem(i); try { invokeCallback(callback, msg.what, args); } catch (RemoteException ignored) { @@ -3645,7 +3645,7 @@ class MountService extends IMountService.Stub args.recycle(); } - private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args) + private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args) throws RemoteException { switch (what) { case MSG_STORAGE_STATE_CHANGED: { @@ -3830,7 +3830,7 @@ class MountService extends IMountService.Stub } } - private final class MountServiceInternalImpl extends MountServiceInternal { + private final class StorageManagerInternalImpl extends StorageManagerInternal { // Not guarded by a lock. private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies = new CopyOnWriteArrayList<>(); diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java index 4f02a23d1e76..cbd7be7343bb 100644 --- a/services/core/java/com/android/server/TextServicesManagerService.java +++ b/services/core/java/com/android/server/TextServicesManagerService.java @@ -30,7 +30,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.AppGlobals; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -159,7 +159,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { int userId = UserHandle.USER_SYSTEM; try { - userId = ActivityManagerNative.getDefault().getCurrentUser().id; + userId = ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e); } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 2825cf9d867b..6ea6fb7c9c03 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -19,7 +19,6 @@ package com.android.server; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IUiModeManager; import android.app.Notification; import android.app.NotificationManager; @@ -39,19 +38,24 @@ import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.service.dreams.Sandman; import android.util.Slog; +import android.view.WindowManagerInternal; +import android.view.WindowManagerPolicy; import java.io.FileDescriptor; import java.io.PrintWriter; import com.android.internal.R; import com.android.internal.app.DisableCarModeActivity; +import com.android.server.power.ShutdownThread; import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; +import com.android.server.wm.WindowManagerService; final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); @@ -297,6 +301,30 @@ final class UiModeManagerService extends SystemService { } @Override + public void setTheme(String theme) { + if (getContext().checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_THEME_OVERLAY) + != PackageManager.PERMISSION_GRANTED) { + Slog.e(TAG, "setTheme requires MODIFY_THEME_OVERLAY permission"); + return; + } + SystemProperties.set("persist.vendor.overlay.theme", theme); + mHandler.post(() -> ShutdownThread.reboot(getContext(), + PowerManager.SHUTDOWN_USER_REQUESTED, false)); + } + + @Override + public String getTheme() { + if (getContext().checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_THEME_OVERLAY) + != PackageManager.PERMISSION_GRANTED) { + Slog.e(TAG, "setTheme requires MODIFY_THEME_OVERLAY permission"); + return null; + } + return SystemProperties.get("persist.vendor.overlay.theme"); + } + + @Override public int getNightMode() { synchronized (mLock) { return mNightMode; @@ -446,7 +474,7 @@ final class UiModeManagerService extends SystemService { mSetUiMode = mConfiguration.uiMode; try { - ActivityManagerNative.getDefault().updateConfiguration(mConfiguration); + ActivityManager.getService().updateConfiguration(mConfiguration); } catch (RemoteException e) { Slog.w(TAG, "Failure communicating with activity manager", e); } @@ -608,7 +636,7 @@ final class UiModeManagerService extends SystemService { Intent homeIntent = buildHomeIntent(category); if (Sandman.shouldStartDockApp(getContext(), homeIntent)) { try { - int result = ActivityManagerNative.getDefault().startActivityWithConfig( + int result = ActivityManager.getService().startActivityWithConfig( null, null, homeIntent, null, null, null, 0, 0, mConfiguration, null, UserHandle.USER_CURRENT); if (result >= ActivityManager.START_SUCCESS) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 78025764b07a..8fd1d2f163ff 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -34,7 +34,6 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -1882,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(); @@ -3999,7 +4004,7 @@ public class AccountManagerService public AccountAndUser[] getRunningAccounts() { final int[] runningUserIds; try { - runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds(); + runningUserIds = ActivityManager.getService().getRunningUserIds(); } catch (RemoteException e) { // Running in system_server; should never happen throw new RuntimeException(e); @@ -4940,7 +4945,7 @@ public class AccountManagerService private int handleIncomingUser(int userId) { try { - return ActivityManagerNative.getDefault().handleIncomingUser( + return ActivityManager.getService().handleIncomingUser( Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null); } catch (RemoteException re) { // Shouldn't happen, local. diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index dc4a52d1c4b7..136e02c434d5 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -348,7 +348,7 @@ public final class ActiveServices { // Before going further -- if this app is not allowed to run in the // background, then at this point we aren't going to let it period. final int allowed = mAm.checkAllowBackgroundLocked( - r.appInfo.uid, r.packageName, callingPid, true); + r.appInfo.uid, r.packageName, callingPid, false); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { Slog.w(TAG, "Background start not allowed: service " + service + " to " + r.name.flattenToShortString() @@ -594,7 +594,8 @@ public final class ActiveServices { for (int i=services.mServicesByName.size()-1; i>=0; i--) { ServiceRecord service = services.mServicesByName.valueAt(i); if (service.appInfo.uid == uid && service.startRequested) { - if (mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, + if (service.appInfo.isEphemeralApp() || + mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, service.packageName) != AppOpsManager.MODE_ALLOWED) { if (stopping == null) { stopping = new ArrayList<>(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2d6832d32af5..c8ed872932c7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -21,10 +21,8 @@ import android.app.ApplicationThreadConstants; import android.app.ContentProviderHolder; import android.app.IActivityManager; import android.app.WaitResult; +import android.graphics.PointF; import android.os.IDeviceIdentifiersPolicyService; -import android.util.Size; -import android.util.TypedValue; -import android.view.DisplayInfo; import com.android.internal.telephony.TelephonyIntents; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -80,7 +78,6 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackId; import android.app.ActivityManager.StackInfo; -import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal.SleepToken; @@ -199,8 +196,8 @@ import android.os.UpdateLock; import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; -import android.os.storage.IMountService; -import android.os.storage.MountServiceInternal; +import android.os.storage.IStorageManager; +import android.os.storage.StorageManagerInternal; import android.os.storage.StorageManager; import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; @@ -221,6 +218,7 @@ import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.Xml; import android.view.Gravity; @@ -293,10 +291,8 @@ import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL; -import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK; import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; import static android.provider.Settings.System.FONT_SCALE; -import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.internal.util.XmlUtils.readBooleanAttribute; @@ -1363,7 +1359,6 @@ public class ActivityManagerService extends IActivityManager.Stub String mOrigDebugApp = null; boolean mOrigWaitForDebugger = false; boolean mAlwaysFinishActivities = false; - boolean mLenientBackgroundCheck = false; boolean mForceResizableActivities; boolean mSupportsMultiWindow; boolean mSupportsFreeformWindowManagement; @@ -1398,6 +1393,27 @@ public class ActivityManagerService extends IActivityManager.Stub boolean foregroundActivities; } + static final class UidObserverRegistration { + final int uid; + final String pkg; + final int which; + final int cutpoint; + + final SparseIntArray lastProcStates; + + UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) { + uid = _uid; + pkg = _pkg; + which = _which; + cutpoint = _cutpoint; + if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) { + lastProcStates = new SparseIntArray(); + } else { + lastProcStates = null; + } + } + } + final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; @@ -1504,7 +1520,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PERSIST_URI_GRANTS_MSG = 38; static final int REQUEST_ALL_PSS_MSG = 39; static final int START_PROFILES_MSG = 40; - static final int UPDATE_TIME = 41; + static final int UPDATE_TIME_PREFERENCE_MSG = 41; static final int SYSTEM_USER_START_MSG = 42; static final int SYSTEM_USER_CURRENT_MSG = 43; static final int ENTER_ANIMATION_COMPLETE_MSG = 44; @@ -1557,6 +1573,10 @@ public class ActivityManagerService extends IActivityManager.Stub int mThumbnailHeight; float mFullscreenThumbnailScale; + /** The aspect ratio bounds of the PIP. */ + float mMinPipAspectRatio; + float mMaxPipAspectRatio; + final ServiceThread mHandlerThread; final MainHandler mHandler; final UiHandler mUiHandler; @@ -2006,15 +2026,18 @@ public class ActivityManagerService extends IActivityManager.Stub } break; } - case UPDATE_TIME: { + case UPDATE_TIME_PREFERENCE_MSG: { + // The user's time format preference might have changed. + // For convenience we re-use the Intent extra values. synchronized (ActivityManagerService.this) { - for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { + for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); if (r.thread != null) { try { - r.thread.updateTimePrefs(msg.arg1 == 0 ? false : true); + r.thread.updateTimePrefs(msg.arg1); } catch (RemoteException ex) { - Slog.w(TAG, "Failed to update preferences for: " + r.info.processName); + Slog.w(TAG, "Failed to update preferences for: " + + r.info.processName); } } } @@ -2077,9 +2100,9 @@ public class ActivityManagerService extends IActivityManager.Stub try { Locale l = (Locale) msg.obj; IBinder service = ServiceManager.getService("mount"); - IMountService mountService = IMountService.Stub.asInterface(service); + IStorageManager storageManager = IStorageManager.Stub.asInterface(service); Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI"); - mountService.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag()); + storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag()); } catch (RemoteException e) { Log.e(TAG, "Error storing locale for decryption UI", e); } @@ -2714,7 +2737,8 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i=0; i<N; i++) { Parcel data2 = Parcel.obtain(); try { - procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, 0); + procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, + Binder.FLAG_ONEWAY); } catch (RemoteException e) { } data2.recycle(); @@ -3578,9 +3602,9 @@ public class ActivityManagerService extends IActivityManager.Stub final IPackageManager pm = AppGlobals.getPackageManager(); permGids = pm.getPackageGids(app.info.packageName, MATCH_DEBUG_TRIAGED_MISSING, app.userId); - MountServiceInternal mountServiceInternal = LocalServices.getService( - MountServiceInternal.class); - mountExternal = mountServiceInternal.getExternalStorageMountMode(uid, + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + mountExternal = storageManagerInternal.getExternalStorageMountMode(uid, app.info.packageName); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -4105,7 +4129,8 @@ public class ActivityManagerService extends IActivityManager.Stub while (i > 0) { i--; final IUidObserver observer = mUidObservers.getBroadcastItem(i); - final int which = (Integer)mUidObservers.getBroadcastCookie(i); + final UidObserverRegistration reg = (UidObserverRegistration) + mUidObservers.getBroadcastCookie(i); if (observer != null) { try { for (int j=0; j<N; j++) { @@ -4122,10 +4147,10 @@ public class ActivityManagerService extends IActivityManager.Stub } if (change == UidRecord.CHANGE_IDLE || change == UidRecord.CHANGE_GONE_IDLE) { - if ((which & ActivityManager.UID_OBSERVER_IDLE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "UID idle uid=" + item.uid); - observer.onUidIdle(item.uid); + observer.onUidIdle(item.uid, item.ephemeral); } if (VALIDATE_UID_STATES && i == 0) { if (validateUid != null) { @@ -4133,7 +4158,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } } else if (change == UidRecord.CHANGE_ACTIVE) { - if ((which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "UID active uid=" + item.uid); observer.onUidActive(item.uid); @@ -4144,10 +4169,13 @@ public class ActivityManagerService extends IActivityManager.Stub } if (change == UidRecord.CHANGE_GONE || change == UidRecord.CHANGE_GONE_IDLE) { - if ((which & ActivityManager.UID_OBSERVER_GONE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "UID gone uid=" + item.uid); - observer.onUidGone(item.uid); + observer.onUidGone(item.uid, item.ephemeral); + } + if (reg.lastProcStates != null) { + reg.lastProcStates.delete(item.uid); } if (VALIDATE_UID_STATES && i == 0) { if (validateUid != null) { @@ -4155,11 +4183,29 @@ public class ActivityManagerService extends IActivityManager.Stub } } } else { - if ((which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid + ": " + item.processState); - observer.onUidStateChanged(item.uid, item.processState); + boolean doReport = true; + if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) { + final int lastState = reg.lastProcStates.get(item.uid, + ActivityManager.PROCESS_STATE_UNKNOWN); + if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) { + final boolean lastAboveCut = lastState <= reg.cutpoint; + final boolean newAboveCut = item.processState <= reg.cutpoint; + doReport = lastAboveCut != newAboveCut; + } else { + doReport = item.processState + != ActivityManager.PROCESS_STATE_NONEXISTENT; + } + } + if (doReport) { + if (reg.lastProcStates != null) { + reg.lastProcStates.put(item.uid, item.processState); + } + observer.onUidStateChanged(item.uid, item.processState); + } } if (VALIDATE_UID_STATES && i == 0) { validateUid.curProcState = validateUid.setProcState @@ -6281,13 +6327,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"); @@ -6447,11 +6498,12 @@ public class ActivityManagerService extends IActivityManager.Stub // SDK can see it. Since access to the serial is now behind a // permission we push down the value. String buildSerial = Build.UNKNOWN; - if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) { + // TODO: SHTOPSHIP Uncomment the check when clients migrate +// if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) { buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface( ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE)) .getSerial(); - } +// } thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profilerInfo, app.instrumentationArguments, app.instrumentationWatcher, @@ -7429,6 +7481,15 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void enterPictureInPictureMode(IBinder token) { + enterPictureInPictureMode(token, DEFAULT_DISPLAY, null /* aspectRatio */); + } + + @Override + public void enterPictureInPictureModeWithAspectRatio(IBinder token, float aspectRatio) { + enterPictureInPictureMode(token, DEFAULT_DISPLAY, aspectRatio); + } + + public void enterPictureInPictureMode(IBinder token, int displayId, Float aspectRatio) { final long origId = Binder.clearCallingIdentity(); try { synchronized(this) { @@ -7438,7 +7499,6 @@ public class ActivityManagerService extends IActivityManager.Stub } final ActivityRecord r = ActivityRecord.forTokenLocked(token); - if (r == null) { throw new IllegalStateException("enterPictureInPictureMode: " + "Can't find activity for token=" + token); @@ -7449,21 +7509,55 @@ public class ActivityManagerService extends IActivityManager.Stub + "Picture-In-Picture not supported for r=" + r); } - // Use the default launch bounds for pinned stack if it doesn't exist yet or use the - // current bounds. - final ActivityStack pinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID); - final Rect bounds = (pinnedStack != null) - ? pinnedStack.mBounds - : mWindowManager.getPictureInPictureDefaultBounds(DEFAULT_DISPLAY); + if (aspectRatio != null && !isValidPictureInPictureAspectRatio(aspectRatio)) { + throw new IllegalArgumentException(String.format("enterPictureInPictureMode: " + + "Aspect ratio is too extreme (must be between %f and %f).", + mMinPipAspectRatio, mMaxPipAspectRatio)); + } - mStackSupervisor.moveActivityToPinnedStackLocked( - r, "enterPictureInPictureMode", bounds); + final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio) + ? mWindowManager.getPictureInPictureBounds(displayId, aspectRatio) + : mWindowManager.getPictureInPictureDefaultBounds(displayId); + mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode", + bounds); } } finally { Binder.restoreCallingIdentity(origId); } } + @Override + public void setPictureInPictureAspectRatio(IBinder token, float aspectRatio) { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized(this) { + final ActivityRecord r = ActivityRecord.forTokenLocked(token); + if (r == null || r.getStack().mStackId != PINNED_STACK_ID) { + throw new IllegalStateException("setPictureInPictureAspectRatio: " + + "Requesting activity must be in picture-in-picture mode."); + } + + if (!isValidPictureInPictureAspectRatio(aspectRatio)) { + throw new IllegalArgumentException(String.format( + "setPictureInPictureAspectRatio: Aspect ratio is too extreme (must be " + + "between %f and %f).", mMinPipAspectRatio, + mMaxPipAspectRatio)); + } + + mWindowManager.setPictureInPictureAspectRatio(aspectRatio); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + private boolean isValidPictureInPictureAspectRatio(Float aspectRatio) { + if (aspectRatio == null) { + return false; + } + return mMinPipAspectRatio <= aspectRatio && aspectRatio <= mMaxPipAspectRatio; + } + // ========================================================= // PROCESS INFO // ========================================================= @@ -7751,38 +7845,43 @@ public class ActivityManagerService extends IActivityManager.Stub public int getAppStartMode(int uid, String packageName) { synchronized (this) { - return checkAllowBackgroundLocked(uid, packageName, -1, true); + return checkAllowBackgroundLocked(uid, packageName, -1, false); } } int checkAllowBackgroundLocked(int uid, String packageName, int callingPid, - boolean allowWhenForeground) { + boolean alwaysRestrict) { UidRecord uidRec = mActiveUids.get(uid); - if (!mLenientBackgroundCheck) { - if (!allowWhenForeground || uidRec == null - || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) { - if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, - packageName) != AppOpsManager.MODE_ALLOWED) { - return ActivityManager.APP_START_MODE_DELAYED; - } + if (uidRec == null || alwaysRestrict || uidRec.idle) { + boolean ephemeral; + if (uidRec == null) { + ephemeral = getPackageManagerInternalLocked().isPackageEphemeral( + UserHandle.getUserId(uid), packageName); + } else { + ephemeral = uidRec.ephemeral; } - } else if (uidRec == null || uidRec.idle) { - if (callingPid >= 0) { - ProcessRecord proc; - synchronized (mPidsSelfLocked) { - proc = mPidsSelfLocked.get(callingPid); + if (ephemeral) { + // We are hard-core about ephemeral apps not running in the background. + return ActivityManager.APP_START_MODE_DISABLED; + } else { + if (callingPid >= 0) { + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(callingPid); + } + if (proc != null && proc.curProcState + < ActivityManager.PROCESS_STATE_RECEIVER) { + // Whoever is instigating this is in the foreground, so we will allow it + // to go through. + return ActivityManager.APP_START_MODE_NORMAL; + } } - if (proc != null && proc.curProcState < ActivityManager.PROCESS_STATE_RECEIVER) { - // Whoever is instigating this is in the foreground, so we will allow it - // to go through. - return ActivityManager.APP_START_MODE_NORMAL; + if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return ActivityManager.APP_START_MODE_DELAYED; } } - if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName) - != AppOpsManager.MODE_ALLOWED) { - return ActivityManager.APP_START_MODE_DELAYED; - } } return ActivityManager.APP_START_MODE_NORMAL; } @@ -8007,7 +8106,12 @@ public class ActivityManagerService extends IActivityManager.Stub // Third... does the caller itself have permission to access // this uri? - if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) { + final int callingAppId = UserHandle.getAppId(callingUid); + if ((callingAppId == Process.SYSTEM_UID) || (callingAppId == Process.ROOT_UID)) { + Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission" + + " grant to " + grantUri + "; use startActivityAsCaller() instead"); + return -1; + } else { if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) { // Require they hold a strong enough Uri permission if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) { @@ -10242,6 +10346,46 @@ public class ActivityManagerService extends IActivityManager.Stub } /** + * Check if the calling UID has a possible chance at accessing the provider + * at the given authority and user. + */ + public String checkContentProviderAccess(String authority, int userId) { + if (userId == UserHandle.USER_ALL) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); + userId = UserHandle.getCallingUserId(); + } + + ProviderInfo cpi = null; + try { + cpi = AppGlobals.getPackageManager().resolveContentProvider(authority, + STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, + userId); + } catch (RemoteException ignored) { + } + if (cpi == null) { + // TODO: make this an outright failure in a future platform release; + // until then anonymous content notifications are unprotected + //return "Failed to find provider " + authority + " for user " + userId; + return null; + } + + ProcessRecord r = null; + synchronized (mPidsSelfLocked) { + r = mPidsSelfLocked.get(Binder.getCallingPid()); + } + if (r == null) { + return "Failed to find PID " + Binder.getCallingPid(); + } + + synchronized (this) { + return checkContentProviderPermissionLocked(cpi, r, userId, true); + } + } + + /** * Check if {@link ProcessRecord} has a possible chance at accessing the * given {@link ProviderInfo}. Final permission checking is always done * in {@link ContentProvider}. @@ -11829,25 +11973,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void setLenientBackgroundCheck(boolean enabled) { - enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT, - "setLenientBackgroundCheck()"); - - long ident = Binder.clearCallingIdentity(); - try { - Settings.Global.putInt( - mContext.getContentResolver(), - Settings.Global.LENIENT_BACKGROUND_CHECK, enabled ? 1 : 0); - - synchronized (this) { - mLenientBackgroundCheck = enabled; - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override public void setActivityController(IActivityController controller, boolean imAMonkey) { enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, "setActivityController()"); @@ -12071,6 +12196,15 @@ public class ActivityManagerService extends IActivityManager.Stub != null; } + @Override + public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras, + IBinder activityToken) { + return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null, receiver, + receiverExtras, activityToken, true, true, + UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) + != null; + } + private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) { @@ -12195,6 +12329,12 @@ public class ActivityManagerService extends IActivityManager.Stub sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content); sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS, pae.receiverExtras); + IBinder autoFillCallback = + extras.getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK); + if (autoFillCallback != null) { + sendBundle.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK, + autoFillCallback); + } } } if (sendReceiver != null) { @@ -12245,13 +12385,15 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void registerUidObserver(IUidObserver observer, int which, String callingPackage) { + public void registerUidObserver(IUidObserver observer, int which, int cutpoint, + String callingPackage) { if (!hasUsageStatsPermission(callingPackage)) { enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, "registerUidObserver"); } synchronized (this) { - mUidObservers.register(observer, which); + mUidObservers.register(observer, new UidObserverRegistration(Binder.getCallingUid(), + callingPackage, which, cutpoint)); } } @@ -12897,7 +13039,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME - && proc.setProcState > ActivityManager.PROCESS_STATE_NONEXISTENT) { + && proc.setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) { proc.notCachedSinceIdle = true; proc.initialIdlePss = 0; proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true, @@ -12944,8 +13086,6 @@ public class ActivityManagerService extends IActivityManager.Stub final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0; final boolean alwaysFinishActivities = Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0; - final boolean lenientBackgroundCheck = - Settings.Global.getInt(resolver, LENIENT_BACKGROUND_CHECK, 0) != 0; final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0; final boolean forceResizable = Settings.Global.getInt( resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0; @@ -12966,7 +13106,6 @@ public class ActivityManagerService extends IActivityManager.Stub mDebugApp = mOrigDebugApp = debugApp; mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger; mAlwaysFinishActivities = alwaysFinishActivities; - mLenientBackgroundCheck = lenientBackgroundCheck; mSupportsLeanbackOnly = supportsLeanbackOnly; mForceResizableActivities = forceResizable; if (supportsMultiWindow || forceResizable) { @@ -12993,6 +13132,10 @@ public class ActivityManagerService extends IActivityManager.Stub com.android.internal.R.dimen.thumbnail_width); mThumbnailHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.thumbnail_height); + mMinPipAspectRatio = res.getFloat( + com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); + mMaxPipAspectRatio = res.getFloat( + com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString( com.android.internal.R.string.config_appsNotReportingCrashes)); mUserController.mUserSwitchUiEnabled = !res.getBoolean( @@ -13433,9 +13576,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 { @@ -14332,7 +14477,7 @@ public class ActivityManagerService extends IActivityManager.Stub pw.print(" "); for (int i=0; i<ass.mStateTimes.length; i++) { long amt = ass.mStateTimes[i]; - if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) { + if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) { amt += now - ass.mLastStateUptime; } if (amt != 0) { @@ -14341,7 +14486,7 @@ public class ActivityManagerService extends IActivityManager.Stub i + ActivityManager.MIN_PROCESS_STATE)); pw.print("="); TimeUtils.formatDuration(amt, pw); - if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) { + if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) { pw.print("*"); } } @@ -14613,6 +14758,43 @@ public class ActivityManagerService extends IActivityManager.Stub pw.print(mode); pw.println(); } } + final int NI = mUidObservers.getRegisteredCallbackCount(); + boolean printed = false; + for (int i=0; i<NI; i++) { + final UidObserverRegistration reg = (UidObserverRegistration) + mUidObservers.getRegisteredCallbackCookie(i); + if (dumpPackage == null || dumpPackage.equals(reg.pkg)) { + if (!printed) { + pw.println(" mUidObservers:"); + printed = true; + } + pw.print(" "); UserHandle.formatUid(pw, reg.uid); + pw.print(" "); pw.print(reg.pkg); pw.print(":"); + if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) { + pw.print(" IDLE"); + } + if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) { + pw.print(" ACT" ); + } + if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) { + pw.print(" GONE"); + } + if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { + pw.print(" STATE"); + pw.print(" (cut="); pw.print(reg.cutpoint); + pw.print(")"); + } + pw.println(); + if (reg.lastProcStates != null) { + final int NJ = reg.lastProcStates.size(); + for (int j=0; j<NJ; j++) { + pw.print(" Last "); + UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j)); + pw.print(": "); pw.println(reg.lastProcStates.valueAt(j)); + } + } + } + } } if (dumpPackage == null) { pw.println(" mWakefulness=" @@ -14702,9 +14884,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (dumpPackage == null) { - if (mAlwaysFinishActivities || mLenientBackgroundCheck) { - pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities - + " mLenientBackgroundCheck=" + mLenientBackgroundCheck); + if (mAlwaysFinishActivities) { + pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities); } if (mController != null) { pw.println(" mController=" + mController @@ -16783,13 +16964,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--) { @@ -17986,11 +18172,20 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.sendEmptyMessage(UPDATE_TIME_ZONE); break; case Intent.ACTION_TIME_CHANGED: - // If the user set the time, let all running processes know. - final int is24Hour = - intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1 - : 0; - mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0)); + // EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between + // the tri-state value it may contain and "unknown". + // For convenience we re-use the Intent extra values. + final int NO_EXTRA_VALUE_FOUND = -1; + final int timeFormatPreferenceMsgValue = intent.getIntExtra( + Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, + NO_EXTRA_VALUE_FOUND /* defaultValue */); + // Only send a message if the time preference is available. + if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) { + Message updateTimePreferenceMsg = + mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG, + timeFormatPreferenceMsgValue, 0); + mHandler.sendMessage(updateTimePreferenceMsg); + } BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { stats.noteCurrentTimeChangedLocked(); @@ -20629,6 +20824,7 @@ public class ActivityManagerService extends IActivityManager.Stub pendingChange.change = change; pendingChange.processState = uidRec != null ? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT; + pendingChange.ephemeral = uidRec.ephemeral; // Directly update the power manager, since we sit on top of it and it is critical // it be kept in sync (so wake locks will be held as soon as appropriate). @@ -20996,8 +21192,11 @@ public class ActivityManagerService extends IActivityManager.Stub } else { // Keeping this process, update its uid. final UidRecord uidRec = app.uidRecord; - if (uidRec != null && uidRec.curProcState > app.curProcState) { - uidRec.curProcState = app.curProcState; + if (uidRec != null) { + uidRec.ephemeral = app.info.isEphemeralApp(); + if (uidRec.curProcState > app.curProcState) { + uidRec.curProcState = app.curProcState; + } } } @@ -21256,6 +21455,63 @@ public class ActivityManagerService extends IActivityManager.Stub } } + @Override + public void makePackageIdle(String packageName, int userId) { + if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: makePackageIdle() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + final int callingPid = Binder.getCallingPid(); + userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(), + userId, true, ALLOW_FULL_ONLY, "makePackageIdle", null); + long callingId = Binder.clearCallingIdentity(); + synchronized(this) { + try { + IPackageManager pm = AppGlobals.getPackageManager(); + int pkgUid = -1; + try { + pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES + | MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM); + } catch (RemoteException e) { + } + if (pkgUid == -1) { + throw new IllegalArgumentException("Unknown package name " + packageName); + } + + if (mLocalPowerManager != null) { + mLocalPowerManager.startUidChanges(); + } + final int appId = UserHandle.getAppId(pkgUid); + final int N = mActiveUids.size(); + for (int i=N-1; i>=0; i--) { + final UidRecord uidRec = mActiveUids.valueAt(i); + final long bgTime = uidRec.lastBackgroundTime; + if (bgTime > 0 && !uidRec.idle) { + if (UserHandle.getAppId(uidRec.uid) == appId) { + if (userId == UserHandle.USER_ALL || + userId == UserHandle.getUserId(uidRec.uid)) { + uidRec.idle = true; + Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid) + + " from package " + packageName + " user " + userId); + doStopUidLocked(uidRec.uid, uidRec); + } + } + } + } + } finally { + if (mLocalPowerManager != null) { + mLocalPowerManager.finishUidChanges(); + } + Binder.restoreCallingIdentity(callingId); + } + } + } + final void idleUids() { synchronized (this) { final int N = mActiveUids.size(); @@ -21871,6 +22127,11 @@ public class ActivityManagerService extends IActivityManager.Stub private final class LocalService extends ActivityManagerInternal { @Override + public String checkContentProviderAccess(String authority, int userId) { + return ActivityManagerService.this.checkContentProviderAccess(authority, userId); + } + + @Override public void onWakefulnessChanged(int wakefulness) { ActivityManagerService.this.onWakefulnessChanged(wakefulness); } @@ -22077,6 +22338,15 @@ public class ActivityManagerService extends IActivityManager.Stub // no need to synchronize(this) just to read & return the value return mSystemReady; } + + @Override + public void notifyKeyguardTrustedChanged() { + synchronized (ActivityManagerService.this) { + if (mKeyguardController.isKeyguardShowing()) { + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + } + } + } } private final class SleepTokenImpl extends SleepToken { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index abeea74ffdae..14b843a8f638 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -80,6 +80,7 @@ import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.view.Display.INVALID_DISPLAY; final class ActivityManagerShellCommand extends ShellCommand { public static final String NO_CLASS_ERROR_CODE = "Error type 3"; @@ -114,6 +115,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private String mProfileFile; private int mSamplingInterval; private boolean mAutoStop; + private int mDisplayId; private int mStackId; final boolean mDumping; @@ -169,6 +171,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runKill(pw); case "kill-all": return runKillAll(pw); + case "make-idle": + return runMakeIdle(pw); case "monitor": return runMonitor(pw); case "hang": @@ -205,8 +209,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return runTrackAssociations(pw); case "untrack-associations": return runUntrackAssociations(pw); - case "lenient-background-check": - return runLenientBackgroundCheck(pw); case "get-uid-state": return getUidState(pw); case "get-config": @@ -249,6 +251,7 @@ final class ActivityManagerShellCommand extends ShellCommand { mSamplingInterval = 0; mAutoStop = false; mUserId = defUser; + mDisplayId = INVALID_DISPLAY; mStackId = INVALID_STACK_ID; return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() { @@ -278,6 +281,8 @@ final class ActivityManagerShellCommand extends ShellCommand { mUserId = UserHandle.parseUserArg(getNextArgRequired()); } else if (opt.equals("--receiver-permission")) { mReceiverPermission = getNextArgRequired(); + } else if (opt.equals("--display")) { + mDisplayId = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("--stack")) { mStackId = Integer.parseInt(getNextArgRequired()); } else { @@ -354,6 +359,10 @@ final class ActivityManagerShellCommand extends ShellCommand { int res; final long startTime = SystemClock.uptimeMillis(); ActivityOptions options = null; + if (mDisplayId != INVALID_DISPLAY) { + options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(mDisplayId); + } if (mStackId != INVALID_STACK_ID) { options = ActivityOptions.makeBasic(); options.setLaunchStackId(mStackId); @@ -853,6 +862,22 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + int runMakeIdle(PrintWriter pw) throws RemoteException { + int userId = UserHandle.USER_ALL; + + String opt; + while ((opt = getNextOption()) != null) { + if (opt.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Error: Unknown option: " + opt); + return -1; + } + } + mInterface.makePackageIdle(getNextArgRequired(), userId); + return 0; + } + static final class MyActivityController extends IActivityController.Stub { final IActivityManager mInterface; final PrintWriter mPw; @@ -1432,22 +1457,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - int runLenientBackgroundCheck(PrintWriter pw) throws RemoteException { - String arg = getNextArg(); - if (arg != null) { - boolean state = Boolean.valueOf(arg) || "1".equals(arg); - mInterface.setLenientBackgroundCheck(state); - } - synchronized (mInternal) { - if (mInternal.mLenientBackgroundCheck) { - pw.println("Lenient background check enabled"); - } else { - pw.println("Lenient background check disabled"); - } - } - return 0; - } - int getUidState(PrintWriter pw) throws RemoteException { mInternal.enforceCallingPermission(android.Manifest.permission.DUMP, "getUidState()"); @@ -2478,8 +2487,6 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Enable association tracking."); pw.println(" untrack-associations"); pw.println(" Disable and clear association tracking."); - pw.println(" lenient-background-check [<true|false>]"); - pw.println(" Optionally controls lenient background check mode, returns current mode."); pw.println(" get-uid-state <UID>"); pw.println(" Gets the process state of an app given its <UID>."); pw.println(" attach-agent <PROCESS> <FILE>"); diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index be8f21d997a5..facfeb67b653 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -16,7 +16,7 @@ import android.os.SystemClock; import android.util.Slog; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 0d7998071e99..473b1a34a892 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1471,7 +1471,7 @@ final class ActivityStack extends ConfigurationContainer { return STACK_INVISIBLE; } - if (mStackSupervisor.isFrontStack(this) || mStackSupervisor.isFocusedStack(this)) { + if (mStackSupervisor.isFrontStackOnDisplay(this) || mStackSupervisor.isFocusedStack(this)) { return STACK_VISIBLE; } @@ -1806,8 +1806,9 @@ final class ActivityStack extends ConfigurationContainer { final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(); final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked(); final boolean showWhenLocked = r.hasShowWhenLockedWindows(); + final boolean dismissKeyguard = r.hasDismissKeyguardWindows(); if (shouldBeVisible) { - if (r.hasDismissKeyguardWindows() && mTopDismissingKeyguardActivity == null) { + if (dismissKeyguard && mTopDismissingKeyguardActivity == null) { mTopDismissingKeyguardActivity = r; } @@ -1819,8 +1820,10 @@ final class ActivityStack extends ConfigurationContainer { } if (keyguardShowing) { - // If keyguard is showing, nothing is visible. - return false; + // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard + // right away. + return shouldBeVisible && mStackSupervisor.mKeyguardController + .canShowActivityWhileKeyguardShowing(dismissKeyguard); } else if (keyguardLocked) { // Show when locked windows above keyguard. diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 8bb0e1a4e240..5d8d79fd52c2 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -38,6 +38,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.FLAG_PRIVATE; +import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS; @@ -90,6 +92,7 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; import android.Manifest; +import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; @@ -609,6 +612,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer /** The top most stack. */ boolean isFrontStack(ActivityStack stack) { + return isFrontOfStackList(stack, mHomeStack.mStacks); + } + + /** The top most stack on its display. */ + boolean isFrontStackOnDisplay(ActivityStack stack) { + return isFrontOfStackList(stack, stack.mActivityContainer.mActivityDisplay.mStacks); + } + + private boolean isFrontOfStackList(ActivityStack stack, List<ActivityStack> stackList) { if (stack == null) { return false; } @@ -617,7 +629,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer if (parent != null) { stack = parent.getStack(); } - return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1)); + return stack == stackList.get((stackList.size() - 1)); } /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */ @@ -1483,16 +1495,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer Slog.w(TAG, message); return false; } - if (options != null && options.getLaunchTaskId() != -1) { - final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS, - callingPid, callingUid); - if (startInTaskPerm != PERMISSION_GRANTED) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with launchTaskId=" - + options.getLaunchTaskId(); - Slog.w(TAG, msg); - throw new SecurityException(msg); + if (options != null) { + if (options.getLaunchTaskId() != INVALID_STACK_ID) { + final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS, + callingPid, callingUid); + if (startInTaskPerm != PERMISSION_GRANTED) { + final String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchTaskId=" + + options.getLaunchTaskId(); + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + // Check if someone tries to launch an activity on a private display with a different + // owner. + final int launchDisplayId = options.getLaunchDisplayId(); + if (launchDisplayId != INVALID_DISPLAY) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId); + if (activityDisplay != null + && (activityDisplay.mDisplay.getFlags() & FLAG_PRIVATE) != 0) { + if (activityDisplay.mDisplay.getOwnerUid() != callingUid) { + final String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchDisplayId=" + + launchDisplayId; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } } } @@ -1937,7 +1968,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer } ActivityStack getStack(int stackId, boolean createStaticStackIfNeeded, boolean createOnTop) { - ActivityContainer activityContainer = mActivityContainers.get(stackId); + final ActivityContainer activityContainer = mActivityContainers.get(stackId); if (activityContainer != null) { return activityContainer.mStack; } @@ -1948,6 +1979,40 @@ public class ActivityStackSupervisor extends ConfigurationContainer return createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop); } + /** + * Get a topmost stack on the display, that is a valid launch stack for specified activity. + * If there is no such stack, new dynamic stack can be created. + * @param displayId Target display. + * @param r Activity that should be launched there. + * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null. + */ + ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r) { + final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + throw new IllegalArgumentException( + "Display with displayId=" + displayId + " not found."); + } + + // Return the topmost valid stack on the display. + for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = activityDisplay.mStacks.get(i); + if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, r)) { + return stack; + } + } + + // If there is no valid stack on the external display - check if new dynamic stack will do. + if (displayId != Display.DEFAULT_DISPLAY) { + final int newDynamicStackId = getNextStackId(); + if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, r)) { + return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/); + } + } + + Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId); + return null; + } + ArrayList<ActivityStack> getStacks() { ArrayList<ActivityStack> allStacks = new ArrayList<>(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { @@ -2120,6 +2185,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer final int size = tasks.size(); if (onTop) { for (int i = 0; i < size; i++) { + final TaskRecord task = tasks.get(i); + if (fromStackId == PINNED_STACK_ID) { + // Update the return-to to reflect where the pinned stack task was moved + // from so that we retain the stack that was previously visible if the + // pinned stack is recreated. See moveActivityToPinnedStackLocked(). + task.setTaskToReturnTo(getFocusedStack().getStackId() == HOME_STACK_ID + ? HOME_ACTIVITY_TYPE : APPLICATION_ACTIVITY_TYPE); + } moveTaskToStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/, "moveTasksToFullscreenStack", ANIMATE, DEFER_RESUME); @@ -2318,11 +2391,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer * Restores a recent task to a stack * @param task The recent task to be restored. * @param stackId The stack to restore the task to (default launch stack will be used - * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}). + * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID} + * or is not a static stack). * @return true if the task has been restored successfully. */ private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) { - if (stackId == INVALID_STACK_ID) { + if (!StackId.isStaticStack(stackId)) { + // If stack is not static (or stack id is invalid) - use the default one. + // This means that tasks that were on external displays will be restored on the + // primary display. stackId = task.getLaunchStackId(); } else if (stackId == DOCKED_STACK_ID && !task.canGoInDockedStack()) { // Preferred stack is the docked stack, but the task can't go in the docked stack. @@ -3496,7 +3573,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer if (activityDisplay != null) { ArrayList<ActivityStack> stacks = activityDisplay.mStacks; for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - stacks.get(stackNdx).mActivityContainer.removeLocked(); + final ActivityStack stack = stacks.get(stackNdx); + // TODO: Implement proper stack removal and ability to choose the behavior - + // remove stack completely or move it to other display. + moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY); } mActivityDisplays.remove(displayId); } @@ -4147,7 +4227,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer } } - /** Remove the stack completely. */ + /** + * Remove the stack completely. Must be called only when there are no tasks left in it, + * as this method does not finish running activities. + */ void removeLocked() { if (DEBUG_STACK) Slog.d(TAG_STACK, "removeLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index e4ec16994507..dff7cefae456 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -31,6 +31,7 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.isStaticStack; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -50,6 +51,8 @@ import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; +import static android.view.Display.INVALID_DISPLAY; + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; @@ -115,6 +118,7 @@ import android.view.Display; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; +import com.android.server.pm.EphemeralResolver; import com.android.server.wm.WindowManagerService; import java.util.ArrayList; @@ -132,9 +136,6 @@ class ActivityStarter { private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; - // TODO b/30204367 remove when the platform fully supports ephemeral applications - private static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false; - private final ActivityManagerService mService; private final ActivityStackSupervisor mSupervisor; private ActivityStartInterceptor mInterceptor; @@ -254,11 +255,7 @@ class ActivityStarter { if (err == ActivityManager.START_SUCCESS) { Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) - + "} from uid " + callingUid - + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ? - Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) : - (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : - container.mActivityDisplay.mDisplayId))); + + "} from uid " + callingUid); } ActivityRecord sourceRecord = null; @@ -458,10 +455,21 @@ class ActivityStarter { // Instead, launch the ephemeral installer. Once the installer is finished, it // starts either the intent we resolved here [on install error] or the ephemeral // app [on install success]. - if (rInfo != null && rInfo.ephemeralResolveInfo != null) { - intent = buildEphemeralInstallerIntent(intent, ephemeralIntent, - rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType, - userId); + if (rInfo != null && rInfo.ephemeralResponse != null) { + final String packageName = + rInfo.ephemeralResponse.resolveInfo.getPackageName(); + final String splitName = rInfo.ephemeralResponse.splitName; + final boolean needsPhaseTwo = rInfo.ephemeralResponse.needsPhase2; + final String token = rInfo.ephemeralResponse.token; + if (needsPhaseTwo) { + // request phase two resolution + mService.getPackageManagerInternalLocked().requestEphemeralResolutionPhaseTwo( + rInfo.ephemeralResponse, ephemeralIntent, resolvedType, intent, + callingPackage, userId); + } + intent = EphemeralResolver.buildEphemeralInstallerIntent(intent, ephemeralIntent, + callingPackage, resolvedType, userId, packageName, splitName, token, + needsPhaseTwo); resolvedType = null; callingUid = realCallingUid; callingPid = realCallingPid; @@ -520,58 +528,6 @@ class ActivityStarter { return err; } - /** - * Builds and returns an intent to launch the ephemeral installer. - */ - private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent, - String ephemeralPackage, String callingPackage, String resolvedType, int userId) { - final Intent nonEphemeralIntent = new Intent(origIntent); - nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL); - // Intent that is launched if the ephemeral package couldn't be installed - // for any reason. - final IIntentSender failureIntentTarget = mService.getIntentSenderLocked( - ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, - Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 1, - new Intent[]{ nonEphemeralIntent }, new String[]{ resolvedType }, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/); - - final Intent ephemeralIntent; - if (USE_DEFAULT_EPHEMERAL_LAUNCHER) { - // Force the intent to be directed to the ephemeral package - ephemeralIntent = new Intent(origIntent); - ephemeralIntent.setPackage(ephemeralPackage); - } else { - // Success intent goes back to the installer - ephemeralIntent = new Intent(launchIntent); - } - - // Intent that is eventually launched if the ephemeral package was - // installed successfully. This will actually be launched by a platform - // broadcast receiver. - final IIntentSender successIntentTarget = mService.getIntentSenderLocked( - ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, - Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 0, - new Intent[]{ ephemeralIntent }, new String[]{ resolvedType }, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/); - - // Finally build the actual intent to launch the ephemeral installer - int flags = launchIntent.getFlags(); - final Intent intent = new Intent(); - intent.setFlags(flags - | Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_CLEAR_TASK - | Intent.FLAG_ACTIVITY_NO_HISTORY - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage); - intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget)); - intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget)); - // TODO: Remove when the platform has fully implemented ephemeral apps - intent.setData(origIntent.getData().buildUpon().clearQuery().build()); - return intent; - } - void postStartActivityUncheckedProcessing( ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord, ActivityStack targetStack) { @@ -1199,6 +1155,14 @@ class ActivityStarter { // since the app transition will not be triggered through the resume channel. mWindowManager.executeAppTransition(); } else { + // If the target stack was not previously focusable (previous top running activity + // on that stack was not visible) then any prior calls to move the stack to the + // will not update the focused stack. If starting the new activity now allows the + // task stack to be focusable, then ensure that we now update the focused stack + // accordingly. + if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) { + mTargetStack.moveToFront("startActivityUnchecked"); + } mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); } @@ -1560,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 @@ -1939,12 +1903,14 @@ class ActivityStarter { // The fullscreen stack can contain any task regardless of if the task is resizeable // or not. So, we let the task go in the fullscreen task if it is the focus stack. + // Same also applies to dynamic stacks, as they behave similar to fullscreen stack. // If the freeform or docked stack has focus, and the activity to be launched is resizeable, // we can also put it in the focused stack. final int focusedStackId = mSupervisor.mFocusedStack.mStackId; final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack()) - || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced()); + || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced()) + || !isStaticStack(focusedStackId); if (canUseFocusedStack && (!newTask || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, @@ -1952,7 +1918,7 @@ class ActivityStarter { return mSupervisor.mFocusedStack; } - // We first try to put the task in the first dynamic stack. + // We first try to put the task in the first dynamic stack on home display. final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks; for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) { stack = homeDisplayStacks.get(stackNdx); @@ -1981,16 +1947,29 @@ class ActivityStarter { return mReuseTask.getStack(); } + final int launchDisplayId = + (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY; + final int launchStackId = (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID; + if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) { + throw new IllegalArgumentException( + "Stack and display id can't be set at the same time."); + } + if (isValidLaunchStackId(launchStackId, r)) { return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP); - } else if (launchStackId == DOCKED_STACK_ID) { + } + if (launchStackId == DOCKED_STACK_ID) { // The preferred launch stack is the docked stack, but it isn't a valid launch stack // for this activity, so we put the activity in the fullscreen stack. return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP); } + if (launchDisplayId != INVALID_DISPLAY) { + // Stack id has higher priority than display id. + return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r); + } if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) { return null; @@ -2034,9 +2013,8 @@ class ActivityStarter { } } - private boolean isValidLaunchStackId(int stackId, ActivityRecord r) { - if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID - || !StackId.isStaticStack(stackId)) { + boolean isValidLaunchStackId(int stackId, ActivityRecord r) { + if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID) { return false; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index c19a5710666b..7a122e6e6d20 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -18,7 +18,7 @@ package com.android.server.am; import com.android.internal.app.ProcessMap; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.os.ProcessCpuTracker; import com.android.server.Watchdog; diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java index c6befd7fbb7a..9e297255c2f9 100644 --- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java @@ -17,7 +17,7 @@ package com.android.server.am; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto; +import com.android.internal.logging.nano.MetricsProto; import android.content.ActivityNotFoundException; import android.content.Context; diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 4e69162e84b9..8104a43cee09 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -36,7 +36,6 @@ import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -595,8 +594,12 @@ public final class BroadcastQueue { } if (!skip) { final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid, - filter.packageName, -1, true); - if (allowed == ActivityManager.APP_START_MODE_DISABLED) { + filter.packageName, -1, false); + if (false && allowed == ActivityManager.APP_START_MODE_DISABLED) { + // XXX should we really not allow this? It means that while we are + // keeping an ephemeral app cached, its registered receivers will stop + // receiving broadcasts after it goes idle... so if it comes back to + // the foreground, it won't know what the current state of those broadcasts is. Slog.w(TAG, "Background execution not allowed: receiving " + r.intent + " to " + filter.receiverList.app @@ -1155,7 +1158,7 @@ public final class BroadcastQueue { if (!skip) { final int allowed = mService.checkAllowBackgroundLocked( info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1, - false); + true); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { // We won't allow this receiver to be launched if the app has been // completely disabled from launches, or it was not explicitly sent diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 722974b62f59..f618fc7c2a29 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -112,3 +112,5 @@ option java_package com.android.server.am # Report changing memory conditions (Values are ProcessStats.ADJ_MEM_FACTOR* constants) 30050 am_mem_factor (Current|1|5),(Previous|1|5) +# UserState has changed +30051 am_user_state_changed (id|1|5),(state|1|5) diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index 98acc9ca4fe1..9d8c3835b33f 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -154,6 +154,14 @@ class KeyguardController { } } + /** + * @return True if we may show an activity while Keyguard is showing because we are in the + * process of dismissing it anyways, false otherwise. + */ + boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) { + return dismissKeyguard && canDismissKeyguard(); + } + private void visibilitiesUpdated() { final boolean lastOccluded = mOccluded; final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity; @@ -215,7 +223,6 @@ class KeyguardController { && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) { mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */); - mKeyguardGoingAway = true; mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mWindowManager.executeAppTransition(); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 2b00f868ea70..1322ecf89baf 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -371,9 +371,6 @@ final class ProcessList { public static String makeProcStateString(int curProcState) { String procState; switch (curProcState) { - case -1: - procState = "N "; - break; case ActivityManager.PROCESS_STATE_PERSISTENT: procState = "P "; break; @@ -425,6 +422,9 @@ final class ProcessList { case ActivityManager.PROCESS_STATE_CACHED_EMPTY: procState = "CE"; break; + case ActivityManager.PROCESS_STATE_NONEXISTENT: + procState = "N "; + break; default: procState = "??"; break; diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index d24c3a52adba..d1a15bdd3829 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -29,6 +29,7 @@ public final class UidRecord { int curProcState; int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; long lastBackgroundTime; + boolean ephemeral; boolean idle; int numProcs; @@ -43,6 +44,7 @@ public final class UidRecord { int uid; int change; int processState; + boolean ephemeral; } ChangeItem pendingChange; @@ -64,6 +66,9 @@ public final class UidRecord { UserHandle.formatUid(sb, uid); sb.append(' '); sb.append(ProcessList.makeProcStateString(curProcState)); + if (ephemeral) { + sb.append(" ephemeral"); + } if (lastBackgroundTime > 0) { sb.append(" bg:"); TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 96978551d56e..a0a04bbc3bd5 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -75,7 +75,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; -import android.os.storage.IMountService; +import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.util.ArraySet; import android.util.IntArray; @@ -735,8 +735,8 @@ final class UserController { } } - private IMountService getMountService() { - return IMountService.Stub.asInterface(ServiceManager.getService("mount")); + private IStorageManager getStorageManager() { + return IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); } /** @@ -980,10 +980,10 @@ final class UserController { // TODO Move this block outside of synchronized if it causes lock contention if (!StorageManager.isUserKeyUnlocked(userId)) { final UserInfo userInfo = getUserInfo(userId); - final IMountService mountService = getMountService(); + final IStorageManager storageManager = getStorageManager(); try { // We always want to unlock user storage, even user is not started yet - mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret); + storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret); } catch (RemoteException | RuntimeException e) { Slog.w(TAG, "Failed to unlock: " + e.getMessage()); } diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java index 48238b6f4cf3..42c31b1a6de4 100644 --- a/services/core/java/com/android/server/am/UserState.java +++ b/services/core/java/com/android/server/am/UserState.java @@ -70,6 +70,7 @@ public final class UserState { public boolean setState(int oldState, int newState) { if (state == oldState) { setState(newState); + EventLogTags.writeAmUserStateChanged(mHandle.getIdentifier(), newState); return true; } else { Slog.w(TAG, "Expected user " + mHandle.getIdentifier() + " in state " diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index eb5e60393526..ac9545c06c10 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -25,7 +25,6 @@ import static android.os.Process.FIRST_APPLICATION_UID; import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.NotificationManager; @@ -273,7 +272,8 @@ public class AudioService extends IAudioService.Stub { 15, // STREAM_BLUETOOTH_SCO 7, // STREAM_SYSTEM_ENFORCED 15, // STREAM_DTMF - 15 // STREAM_TTS + 15, // STREAM_TTS + 15 // STREAM_ACCESSIBILITY }; /** Minimum volume index values for audio streams */ @@ -287,7 +287,8 @@ public class AudioService extends IAudioService.Stub { 0, // STREAM_BLUETOOTH_SCO 0, // STREAM_SYSTEM_ENFORCED 0, // STREAM_DTMF - 0 // STREAM_TTS + 0, // STREAM_TTS + 0 // STREAM_ACCESSIBILITY }; /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings @@ -309,7 +310,8 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_RING, // STREAM_DTMF - AudioSystem.STREAM_MUSIC // STREAM_TTS + AudioSystem.STREAM_MUSIC, // STREAM_TTS + AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY }; private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] { AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL @@ -321,7 +323,8 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_MUSIC, // STREAM_DTMF - AudioSystem.STREAM_MUSIC // STREAM_TTS + AudioSystem.STREAM_MUSIC, // STREAM_TTS + AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY }; private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL @@ -333,7 +336,8 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_RING, // STREAM_DTMF - AudioSystem.STREAM_MUSIC // STREAM_TTS + AudioSystem.STREAM_MUSIC, // STREAM_TTS + AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY }; private int[] mStreamVolumeAlias; @@ -352,6 +356,7 @@ public class AudioService extends IAudioService.Stub { AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS + AppOpsManager.OP_AUDIO_ACCESSIBILITY_VOLUME, // STREAM_ACCESSIBILITY }; private final boolean mUseFixedVolume; @@ -1706,7 +1711,7 @@ public class AudioService extends IAudioService.Stub { private int getCurrentUserId() { final long ident = Binder.clearCallingIdentity(); try { - UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + UserInfo currentUser = ActivityManager.getService().getCurrentUser(); return currentUser.id; } catch (RemoteException e) { // Activity manager not running, nothing we can do assume user 0. @@ -5124,7 +5129,7 @@ public class AudioService extends IAudioService.Stub { final long ident = Binder.clearCallingIdentity(); try { - ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); + ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } @@ -5463,7 +5468,7 @@ public class AudioService extends IAudioService.Stub { } try { final int uid = pkg.applicationInfo.uid; - ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid), + ActivityManager.getService().killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid), "killBackgroundUserProcessesWithAudioRecordPermission"); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 5772a57d79aa..8d4f0a925d8d 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -16,7 +16,7 @@ package com.android.server.clipboard; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.IActivityManager; @@ -71,7 +71,7 @@ public class ClipboardService extends SystemService { public ClipboardService(Context context) { super(context); - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); mPm = getContext().getPackageManager(); mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java index f1d01e06911a..372b2d8e566e 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java @@ -29,14 +29,14 @@ import android.net.metrics.NetworkEvent; import android.net.metrics.RaEvent; import android.net.metrics.ValidationProbeEvent; import android.os.Parcelable; -import com.android.server.connectivity.metrics.IpConnectivityLogClass; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent; -import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog; -import static com.android.server.connectivity.metrics.IpConnectivityLogClass.NetworkId; +import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; +import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog; +import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.NetworkId; /** {@hide} */ final public class IpConnectivityEventBuilder { @@ -136,96 +136,107 @@ final public class IpConnectivityEventBuilder { } private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) { - out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent(); - out.dhcpEvent.ifName = in.ifName; - out.dhcpEvent.errorCode = in.errorCode; + IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent(); + dhcpEvent.ifName = in.ifName; + dhcpEvent.setErrorCode(in.errorCode); + out.setDhcpEvent(dhcpEvent); } private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) { - out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent(); - out.dhcpEvent.ifName = in.ifName; - out.dhcpEvent.stateTransition = in.msg; - out.dhcpEvent.durationMs = in.durationMs; + IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent(); + dhcpEvent.ifName = in.ifName; + dhcpEvent.setStateTransition(in.msg); + dhcpEvent.durationMs = in.durationMs; + out.setDhcpEvent(dhcpEvent); } private static void setDnsEvent(IpConnectivityEvent out, DnsEvent in) { - out.dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch(); - out.dnsLookupBatch.networkId = netIdOf(in.netId); - out.dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes); - out.dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes); - out.dnsLookupBatch.latenciesMs = in.latenciesMs; + IpConnectivityLogClass.DNSLookupBatch dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch(); + dnsLookupBatch.networkId = netIdOf(in.netId); + dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes); + dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes); + dnsLookupBatch.latenciesMs = in.latenciesMs; + out.setDnsLookupBatch(dnsLookupBatch); } private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) { - out.ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent(); - out.ipProvisioningEvent.ifName = in.ifName; - out.ipProvisioningEvent.eventType = in.eventType; - out.ipProvisioningEvent.latencyMs = (int) in.durationMs; + IpConnectivityLogClass.IpProvisioningEvent ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent(); + ipProvisioningEvent.ifName = in.ifName; + ipProvisioningEvent.eventType = in.eventType; + ipProvisioningEvent.latencyMs = (int) in.durationMs; + out.setIpProvisioningEvent(ipProvisioningEvent); } private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) { - out.ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent(); - out.ipReachabilityEvent.ifName = in.ifName; - out.ipReachabilityEvent.eventType = in.eventType; + IpConnectivityLogClass.IpReachabilityEvent ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent(); + ipReachabilityEvent.ifName = in.ifName; + ipReachabilityEvent.eventType = in.eventType; + out.setIpReachabilityEvent(ipReachabilityEvent); } private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) { - out.defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent(); - out.defaultNetworkEvent.networkId = netIdOf(in.netId); - out.defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId); - out.defaultNetworkEvent.transportTypes = in.transportTypes; - out.defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in); + IpConnectivityLogClass.DefaultNetworkEvent defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent(); + defaultNetworkEvent.networkId = netIdOf(in.netId); + defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId); + defaultNetworkEvent.transportTypes = in.transportTypes; + defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in); + out.setDefaultNetworkEvent(defaultNetworkEvent); } private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) { - out.networkEvent = new IpConnectivityLogClass.NetworkEvent(); - out.networkEvent.networkId = netIdOf(in.netId); - out.networkEvent.eventType = in.eventType; - out.networkEvent.latencyMs = (int) in.durationMs; + IpConnectivityLogClass.NetworkEvent networkEvent = new IpConnectivityLogClass.NetworkEvent(); + networkEvent.networkId = netIdOf(in.netId); + networkEvent.eventType = in.eventType; + networkEvent.latencyMs = (int) in.durationMs; + out.setNetworkEvent(networkEvent); } private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) { - out.validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent(); - out.validationProbeEvent.networkId = netIdOf(in.netId); - out.validationProbeEvent.latencyMs = (int) in.durationMs; - out.validationProbeEvent.probeType = in.probeType; - out.validationProbeEvent.probeResult = in.returnCode; + IpConnectivityLogClass.ValidationProbeEvent validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent(); + validationProbeEvent.networkId = netIdOf(in.netId); + validationProbeEvent.latencyMs = (int) in.durationMs; + validationProbeEvent.probeType = in.probeType; + validationProbeEvent.probeResult = in.returnCode; + out.setValidationProbeEvent(validationProbeEvent); } private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) { - out.apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent(); - out.apfProgramEvent.lifetime = in.lifetime; - out.apfProgramEvent.filteredRas = in.filteredRas; - out.apfProgramEvent.currentRas = in.currentRas; - out.apfProgramEvent.programLength = in.programLength; + IpConnectivityLogClass.ApfProgramEvent apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent(); + apfProgramEvent.lifetime = in.lifetime; + apfProgramEvent.filteredRas = in.filteredRas; + apfProgramEvent.currentRas = in.currentRas; + apfProgramEvent.programLength = in.programLength; if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) { - out.apfProgramEvent.dropMulticast = true; + apfProgramEvent.dropMulticast = true; } if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) { - out.apfProgramEvent.hasIpv4Addr = true; + apfProgramEvent.hasIpv4Addr = true; } + out.setApfProgramEvent(apfProgramEvent); } private static void setApfStats(IpConnectivityEvent out, ApfStats in) { - out.apfStatistics = new IpConnectivityLogClass.ApfStatistics(); - out.apfStatistics.durationMs = in.durationMs; - out.apfStatistics.receivedRas = in.receivedRas; - out.apfStatistics.matchingRas = in.matchingRas; - out.apfStatistics.droppedRas = in.droppedRas; - out.apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas; - out.apfStatistics.parseErrors = in.parseErrors; - out.apfStatistics.programUpdates = in.programUpdates; - out.apfStatistics.maxProgramSize = in.maxProgramSize; + IpConnectivityLogClass.ApfStatistics apfStatistics = new IpConnectivityLogClass.ApfStatistics(); + apfStatistics.durationMs = in.durationMs; + apfStatistics.receivedRas = in.receivedRas; + apfStatistics.matchingRas = in.matchingRas; + apfStatistics.droppedRas = in.droppedRas; + apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas; + apfStatistics.parseErrors = in.parseErrors; + apfStatistics.programUpdates = in.programUpdates; + apfStatistics.maxProgramSize = in.maxProgramSize; + out.setApfStatistics(apfStatistics); } private static void setRaEvent(IpConnectivityEvent out, RaEvent in) { - out.raEvent = new IpConnectivityLogClass.RaEvent(); - out.raEvent.routerLifetime = in.routerLifetime; - out.raEvent.prefixValidLifetime = in.prefixValidLifetime; - out.raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime; - out.raEvent.routeInfoLifetime = in.routeInfoLifetime; - out.raEvent.rdnssLifetime = in.rdnssLifetime; - out.raEvent.dnsslLifetime = in.dnsslLifetime; + IpConnectivityLogClass.RaEvent raEvent = new IpConnectivityLogClass.RaEvent(); + raEvent.routerLifetime = in.routerLifetime; + raEvent.prefixValidLifetime = in.prefixValidLifetime; + raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime; + raEvent.routeInfoLifetime = in.routeInfoLifetime; + raEvent.rdnssLifetime = in.rdnssLifetime; + raEvent.dnsslLifetime = in.dnsslLifetime; + out.setRaEvent(raEvent); } private static int[] bytesToInts(byte[] in) { diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 641c62fe2a4d..42f439c242f8 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -42,7 +42,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.function.ToIntFunction; -import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent; +import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; /** {@hide} */ final public class IpConnectivityMetrics extends SystemService { diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 0beb227e5825..6d96a1015aa2 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -71,6 +71,7 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.connectivity.tethering.IControlsTethering; import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; +import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices; import com.android.server.connectivity.tethering.TetherInterfaceStateMachine; import com.android.server.net.BaseNetworkObserver; @@ -1939,7 +1940,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering private void trackNewTetherableInterface(String iface, int interfaceType) { TetherState tetherState; tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper, - interfaceType, mNMService, mStatsService, this)); + interfaceType, mNMService, mStatsService, this, + new IPv6TetheringInterfaceServices(iface, mNMService))); mTetherStates.put(iface, tetherState); tetherState.mStateMachine.start(); } diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java index c2c1a8c5fef7..dec2f77b6455 100644 --- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java +++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java @@ -45,7 +45,7 @@ import java.util.Objects; /** * @hide */ -class IPv6TetheringInterfaceServices { +public class IPv6TetheringInterfaceServices { private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); private static final int RFC7421_IP_PREFIX_LENGTH = 64; @@ -59,7 +59,7 @@ class IPv6TetheringInterfaceServices { private RouterAdvertisementDaemon mRaDaemon; private RaParams mLastRaParams; - IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) { + public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) { mIfName = ifname; mNMService = nms; } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 6ca4e271ec55..37221a971ad1 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -94,14 +94,14 @@ public class TetherInterfaceStateMachine extends StateMachine { public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType, INetworkManagementService nMService, INetworkStatsService statsService, - IControlsTethering tetherController) { + IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) { super(ifaceName, looper); mNMService = nMService; mStatsService = statsService; mTetherController = tetherController; mIfaceName = ifaceName; mInterfaceType = interfaceType; - mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService); + mIPv6TetherSvc = ipv6Svc; mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; mInitialState = new InitialState(); diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 07276298d66d..886c97f4ce17 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -20,12 +20,11 @@ import android.Manifest; import android.accounts.Account; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityManagerNative; +import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.job.JobInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.IContentService; @@ -66,7 +65,6 @@ import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -296,24 +294,15 @@ public final class ContentService extends IContentService.Stub { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); - final int callingUserHandle = UserHandle.getCallingUserId(); - // Registering an observer for any user other than the calling user requires uri grant or - // cross user permission - if (callingUserHandle != userHandle) { - if (checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle) - != PackageManager.PERMISSION_GRANTED) { - enforceCrossUserPermission(userHandle, - "no permission to observe other users' provider view"); - } - } - if (userHandle < 0) { - if (userHandle == UserHandle.USER_CURRENT) { - userHandle = ActivityManager.getCurrentUser(); - } else if (userHandle != UserHandle.USER_ALL) { - throw new InvalidParameterException("Bad user handle for registerContentObserver: " - + userHandle); - } + userHandle = handleIncomingUser(uri, pid, uid, + Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle); + + final String msg = LocalServices.getService(ActivityManagerInternal.class) + .checkContentProviderAccess(uri.getAuthority(), userHandle); + if (msg != null) { + Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg); + return; } synchronized (mRootNode) { @@ -363,22 +352,15 @@ public final class ContentService extends IContentService.Stub { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final int callingUserHandle = UserHandle.getCallingUserId(); - // Notify for any user other than the caller requires uri grant or cross user permission - if (callingUserHandle != userHandle) { - if (checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - userHandle) != PackageManager.PERMISSION_GRANTED) { - enforceCrossUserPermission(userHandle, "no permission to notify other users"); - } - } - // We passed the permission check; resolve pseudouser targets as appropriate - if (userHandle < 0) { - if (userHandle == UserHandle.USER_CURRENT) { - userHandle = ActivityManager.getCurrentUser(); - } else if (userHandle != UserHandle.USER_ALL) { - throw new InvalidParameterException("Bad user handle for notifyChange: " - + userHandle); - } + userHandle = handleIncomingUser(uri, pid, uid, + Intent.FLAG_GRANT_WRITE_URI_PERMISSION, userHandle); + + final String msg = LocalServices.getService(ActivityManagerInternal.class) + .checkContentProviderAccess(uri.getAuthority(), userHandle); + if (msg != null) { + Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg); + return; } // This makes it so that future permission checks will be in the context of this @@ -434,7 +416,7 @@ public final class ContentService extends IContentService.Stub { private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) { try { - return ActivityManagerNative.getDefault().checkUriPermission( + return ActivityManager.getService().checkUriPermission( uri, pid, uid, modeFlags, userHandle, null); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; @@ -1143,6 +1125,27 @@ public final class ContentService extends IContentService.Stub { } } + private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, int userId) { + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + if (userId == UserHandle.USER_ALL) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); + } else if (userId < 0) { + throw new IllegalArgumentException("Invalid user: " + userId); + } else if (userId != UserHandle.getCallingUserId()) { + if (checkUriPermission(uri, pid, uid, modeFlags, + userId) != PackageManager.PERMISSION_GRANTED) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); + } + } + + return userId; + } + /** * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL * permission, if the userHandle is not for the caller. diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 03d95b2c1903..11a3f1189129 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -21,7 +21,6 @@ import android.accounts.AccountAndUser; import android.accounts.AccountManager; import android.accounts.AccountManagerInternal; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.Notification; import android.app.NotificationManager; @@ -1020,7 +1019,7 @@ public class SyncManager { final int owningUid = syncAdapterInfo.uid; final String owningPackage = syncAdapterInfo.componentName.getPackageName(); try { - if (ActivityManagerNative.getDefault().getAppStartMode(owningUid, + if (ActivityManager.getService().getAppStartMode(owningUid, owningPackage) == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":" + syncAdapterInfo.componentName diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 971989b21219..9c762cce7e0f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -220,6 +220,11 @@ public final class DisplayManagerService extends SystemService { private final DisplayViewport mTempDefaultViewport = new DisplayViewport(); private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport(); + // The default color mode for default displays. Overrides the usual + // Display.Display.COLOR_MODE_DEFAULT for displays with the + // DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY flag set. + private final int mDefaultDisplayDefaultColorMode; + // Temporary list of deferred work to perform when setting the display state. // Only used by requestDisplayState. The field is self-synchronized and only // intended for use inside of the requestGlobalDisplayStateInternal function. @@ -232,6 +237,8 @@ public final class DisplayManagerService extends SystemService { mUiHandler = UiThread.getHandler(); mDisplayAdapterListener = new DisplayAdapterListener(); mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); + mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger( + com.android.internal.R.integer.config_defaultDisplayDefaultColorMode); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting(); @@ -703,6 +710,14 @@ public final class DisplayManagerService extends SystemService { } if (display != null && display.getPrimaryDisplayDeviceLocked() == device) { int colorMode = mPersistentDataStore.getColorMode(device); + if (colorMode == Display.COLOR_MODE_INVALID) { + if ((device.getDisplayDeviceInfoLocked().flags + & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) { + colorMode = mDefaultDisplayDefaultColorMode; + } else { + colorMode = Display.COLOR_MODE_DEFAULT; + } + } display.setRequestedColorModeLocked(colorMode); } scheduleTraversalLocked(false); @@ -1043,6 +1058,7 @@ public final class DisplayManagerService extends SystemService { pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); pw.println(" mDefaultViewport=" + mDefaultViewport); pw.println(" mExternalTouchViewport=" + mExternalTouchViewport); + pw.println(" mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode); pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount); diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java index 5616fb97bad7..47701b99860a 100644 --- a/services/core/java/com/android/server/display/PersistentDataStore.java +++ b/services/core/java/com/android/server/display/PersistentDataStore.java @@ -183,11 +183,11 @@ final class PersistentDataStore { public int getColorMode(DisplayDevice device) { if (!device.hasStableUniqueId()) { - return Display.COLOR_MODE_DEFAULT; + return Display.COLOR_MODE_INVALID; } DisplayState state = getDisplayState(device.getUniqueId(), false); if (state == null) { - return Display.COLOR_MODE_DEFAULT; + return Display.COLOR_MODE_INVALID; } return state.getColorMode(); } diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index 393199dd6183..fbad8dede87d 100644 --- a/services/core/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -17,7 +17,7 @@ package com.android.server.dreams; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import android.content.ComponentName; import android.content.Context; diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index 5297589c4795..d65e25785e39 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -17,7 +17,7 @@ package com.android.server.fingerprint; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import android.content.Context; import android.hardware.fingerprint.Fingerprint; diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java index 640a46fb656f..c70ca7f5b28b 100644 --- a/services/core/java/com/android/server/fingerprint/EnrollClient.java +++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java @@ -25,7 +25,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.util.Arrays; diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 49c414032023..273bc6484724 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -19,7 +19,6 @@ package com.android.server.fingerprint; import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.PendingIntent; @@ -465,7 +464,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe private boolean isForegroundActivity(int uid, int pid) { try { List<RunningAppProcessInfo> procs = - ActivityManagerNative.getDefault().getRunningAppProcesses(); + ActivityManager.getService().getRunningAppProcesses(); int N = procs.size(); for (int i = 0; i < N; i++) { RunningAppProcessInfo proc = procs.get(i); @@ -1072,7 +1071,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe private void listenForUserSwitches() { try { - ActivityManagerNative.getDefault().registerUserSwitchObserver( + ActivityManager.getService().registerUserSwitchObserver( new SynchronousUserSwitchObserver() { @Override public void onUserSwitching(int newUserId) throws RemoteException { diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index 603402e32bfb..a2a55e532ef4 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -188,12 +188,6 @@ final class Constants { static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID; static final int PATH_INTERNAL = HdmiDeviceInfo.PATH_INTERNAL; - // Send result codes. It should be consistent with hdmi_cec.h's send_message error code. - static final int SEND_RESULT_SUCCESS = 0; - static final int SEND_RESULT_NAK = 1; - static final int SEND_RESULT_BUSY = 2; - static final int SEND_RESULT_FAILURE = 3; - // Strategy for device polling. // Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX. static final int POLL_STRATEGY_MASK = 0x3; // first and second bit. @@ -231,26 +225,7 @@ final class Constants { static final int RECORDING_TYPE_OWN_SOURCE = 4; // Definitions used for setOption(). These should be in sync with the definition - // in hardware/libhardware/include/hardware/{hdmi_cec.h,mhl.h}. - - // TV gets turned on by incoming <Text/Image View On>. enabled by default. - // If set to disabled, TV won't turn on automatically. - static final int OPTION_CEC_AUTO_WAKEUP = 1; - - // If set to disabled, all CEC commands are discarded. - static final int OPTION_CEC_ENABLE = 2; - - // If set to disabled, system service yields control of CEC to sub-microcontroller. - // If enabled, it takes the control back. - static final int OPTION_CEC_SERVICE_CONTROL = 3; - - // Put other devices to standby when TV goes to standby. enabled by default. - // If set to disabled, TV doesn't send <Standby> to other devices. - static final int OPTION_CEC_AUTO_DEVICE_OFF = 4; - - // Passes the language used in the system when updated. The value to use is the 3 byte - // code as defined in ISO/FDIS 639-2. - static final int OPTION_CEC_SET_LANGUAGE = 5; + // in hardware/libhardware/include/hardware/mhl.h. // If set to disabled, TV does not switch ports when mobile device is connected. static final int OPTION_MHL_INPUT_SWITCHING = 101; diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index 5a1d896c74a6..c684a56ec5d4 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -16,13 +16,13 @@ package com.android.server.hdmi; -import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiTvClient; import android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.RemoteException; import android.util.Slog; - import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** @@ -95,7 +95,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { sendCommand(mGivePowerStatus, new SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); finish(); return; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 687aaa1f4b22..461a9b0636e4 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -17,23 +17,23 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.tv.cec.V1_0.Result; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.util.Slog; import android.util.SparseArray; - import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Predicate; import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; - -import libcore.util.EmptyArray; - import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import libcore.util.EmptyArray; +import sun.util.locale.LanguageTag; /** * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command @@ -256,7 +256,7 @@ final class HdmiCecController { if (HdmiUtils.isValidAddress(newLogicalAddress)) { return nativeAddLogicalAddress(mNativePtr, newLogicalAddress); } else { - return -1; + return Result.FAILURE_INVALID_ARGS; } } @@ -320,13 +320,27 @@ final class HdmiCecController { * Set an option to CEC HAL. * * @param flag key of option - * @param value value of option + * @param enabled whether to enable/disable the given option. + */ + @ServiceThreadOnly + void setOption(int flag, boolean enabled) { + assertRunOnServiceThread(); + HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled); + nativeSetOption(mNativePtr, flag, enabled); + } + + /** + * Informs CEC HAL about the current system language. + * + * @param language Three-letter code defined in ISO/FDIS 639-2. Must be lowercase letters. */ @ServiceThreadOnly - void setOption(int flag, int value) { + void setLanguage(String language) { assertRunOnServiceThread(); - HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value); - nativeSetOption(mNativePtr, flag, value); + if (!LanguageTag.isLanguage(language)) { + return; + } + nativeSetLanguage(mNativePtr, language); } /** @@ -336,9 +350,9 @@ final class HdmiCecController { * @param enabled whether to enable/disable ARC */ @ServiceThreadOnly - void setAudioReturnChannel(int port, boolean enabled) { + void enableAudioReturnChannel(int port, boolean enabled) { assertRunOnServiceThread(); - nativeSetAudioReturnChannel(mNativePtr, port, enabled); + nativeEnableAudioReturnChannel(mNativePtr, port, enabled); } /** @@ -472,9 +486,9 @@ final class HdmiCecController { // <Polling Message> is a message which has empty body. int ret = nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY); - if (ret == Constants.SEND_RESULT_SUCCESS) { + if (ret == SendMessageResult.SUCCESS) { return true; - } else if (ret != Constants.SEND_RESULT_NAK) { + } else if (ret != SendMessageResult.NACK) { // Unusual failure HdmiLogger.warning("Failed to send a polling message(%d->%d) with return code %d", sourceAddress, destinationAddress, ret); @@ -572,17 +586,17 @@ final class HdmiCecController { HdmiLogger.debug("[S]:" + cecMessage); byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); int i = 0; - int errorCode = Constants.SEND_RESULT_SUCCESS; + int errorCode = SendMessageResult.SUCCESS; do { errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(), cecMessage.getDestination(), body); - if (errorCode == Constants.SEND_RESULT_SUCCESS) { + if (errorCode == SendMessageResult.SUCCESS) { break; } } while (i++ < HdmiConfig.RETRANSMISSION_COUNT); final int finalError = errorCode; - if (finalError != Constants.SEND_RESULT_SUCCESS) { + if (finalError != SendMessageResult.SUCCESS) { Slog.w(TAG, "Failed to send " + cecMessage); } if (callback != null) { @@ -636,7 +650,8 @@ final class HdmiCecController { private static native int nativeGetVersion(long controllerPtr); private static native int nativeGetVendorId(long controllerPtr); private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr); - private static native void nativeSetOption(long controllerPtr, int flag, int value); - private static native void nativeSetAudioReturnChannel(long controllerPtr, int port, boolean flag); + private static native void nativeSetOption(long controllerPtr, int flag, boolean enabled); + private static native void nativeSetLanguage(long controllerPtr, String language); + private static native void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag); private static native boolean nativeIsConnected(long controllerPtr, int port); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 43d8bac73a50..c85d97962a22 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -36,6 +36,7 @@ import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.HdmiRecordSources; import android.hardware.hdmi.HdmiTimerRecordSources; import android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.media.AudioManager; import android.media.AudioSystem; import android.media.tv.TvInputInfo; @@ -46,7 +47,6 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; - import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; @@ -57,9 +57,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.HashMap; /** * Represent a logical device of type TV residing in Android system. @@ -910,7 +910,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled); boolean oldStatus = mArcEstablished; // 1. Enable/disable ARC circuit. - setAudioReturnChannel(enabled); + enableAudioReturnChannel(enabled); // 2. Notify arc status to audio service. notifyArcStatusToAudioService(enabled); // 3. Update arc status; @@ -922,11 +922,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * Switch hardware ARC circuit in the system. */ @ServiceThreadOnly - void setAudioReturnChannel(boolean enabled) { + void enableAudioReturnChannel(boolean enabled) { assertRunOnServiceThread(); HdmiDeviceInfo avr = getAvrDeviceInfo(); if (avr != null) { - mService.setAudioReturnChannel(avr.getPortId(), enabled); + mService.enableAudioReturnChannel(avr.getPortId(), enabled); } } @@ -1870,7 +1870,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.sendCecCommand(message, new SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { announceClearTimerRecordingResult(recorderAddress, CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 72ee218fba2c..18f1b6c0513c 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -20,10 +20,6 @@ import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; import static com.android.server.hdmi.Constants.DISABLED; import static com.android.server.hdmi.Constants.ENABLED; -import static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; -import static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; -import static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; -import static com.android.server.hdmi.Constants.OPTION_CEC_SET_LANGUAGE; import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; @@ -49,6 +45,8 @@ import android.hardware.hdmi.IHdmiMhlVendorCommandListener; import android.hardware.hdmi.IHdmiRecordListener; import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; import android.hardware.hdmi.IHdmiVendorCommandListener; +import android.hardware.tv.cec.V1_0.OptionKey; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.media.AudioManager; import android.media.tv.TvInputManager; import android.media.tv.TvInputManager.TvInputCallback; @@ -69,7 +67,6 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; - import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; @@ -77,11 +74,6 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; -import com.android.server.hdmi.SelectRequestBuffer.DeviceSelectRequest; -import com.android.server.hdmi.SelectRequestBuffer.PortSelectRequest; - -import libcore.util.EmptyArray; - import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -89,6 +81,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; +import libcore.util.EmptyArray; /** * Provides a service for sending and processing HDMI control messages, @@ -123,9 +116,10 @@ public final class HdmiControlService extends SystemService { * * @param error result of send request. * <ul> - * <li>{@link Constants#SEND_RESULT_SUCCESS} - * <li>{@link Constants#SEND_RESULT_NAK} - * <li>{@link Constants#SEND_RESULT_FAILURE} + * <li>{@link SendMessageResult#SUCCESS} + * <li>{@link SendMessageResult#NACK} + * <li>{@link SendMessageResult#BUSY} + * <li>{@link SendMessageResult#FAIL} * </ul> */ void onSendCompleted(int error); @@ -466,7 +460,7 @@ public final class HdmiControlService extends SystemService { mWakeUpMessageReceived = false; if (isTvDeviceEnabled()) { - mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); + mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup()); } int reason = -1; switch (initiatedBy) { @@ -519,7 +513,7 @@ public final class HdmiControlService extends SystemService { if (isTvDeviceEnabled()) { tv().setAutoWakeup(enabled); } - setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); + setCecOption(OptionKey.WAKEUP, enabled); break; case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: for (int type : mLocalDevices) { @@ -556,8 +550,8 @@ public final class HdmiControlService extends SystemService { private void initializeCec(int initiatedBy) { mAddressAllocated = false; - mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); - mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(mLanguage)); + mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true); + mCecController.setLanguage(mLanguage); initializeLocalDevices(initiatedBy); } @@ -842,7 +836,7 @@ public final class HdmiControlService extends SystemService { } else { HdmiLogger.error("Invalid message type:" + command); if (callback != null) { - callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); + callback.onSendCompleted(SendMessageResult.FAIL); } } } @@ -884,8 +878,8 @@ public final class HdmiControlService extends SystemService { return dispatchMessageToLocalDevice(message); } - void setAudioReturnChannel(int portId, boolean enabled) { - mCecController.setAudioReturnChannel(portId, enabled); + void enableAudioReturnChannel(int portId, boolean enabled) { + mCecController.enableAudioReturnChannel(portId, enabled); } @ServiceThreadOnly @@ -2079,7 +2073,7 @@ public final class HdmiControlService extends SystemService { if (isTvDeviceEnabled()) { tv().broadcastMenuLanguage(language); - mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language)); + mCecController.setLanguage(language); } } @@ -2123,7 +2117,7 @@ public final class HdmiControlService extends SystemService { } mStandbyMessageReceived = false; mAddressAllocated = false; - mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); + mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false); mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED); } @@ -2216,7 +2210,7 @@ public final class HdmiControlService extends SystemService { } @ServiceThreadOnly - void setCecOption(int key, int value) { + void setCecOption(int key, boolean value) { assertRunOnServiceThread(); mCecController.setOption(key, value); } @@ -2249,7 +2243,7 @@ public final class HdmiControlService extends SystemService { @ServiceThreadOnly private void enableHdmiControlService() { - mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); + mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true); mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED); initializeCec(INITIATED_BY_ENABLE_CEC); @@ -2264,7 +2258,7 @@ public final class HdmiControlService extends SystemService { mCecController.flush(new Runnable() { @Override public void run() { - mCecController.setOption(OPTION_CEC_ENABLE, DISABLED); + mCecController.setOption(OptionKey.ENABLE_CEC, false); mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED); clearLocalDevices(); } diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java index 9aa9290e7f72..8b1641187ac8 100644 --- a/services/core/java/com/android/server/hdmi/HdmiUtils.java +++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java @@ -291,18 +291,4 @@ final class HdmiUtils { info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(), info.getVendorId(), info.getDisplayName(), newPowerStatus); } - - /** - * Convert 3 byte-long language code in string to integer representation. - * English(eng), for example, is converted to 0x656e67. - * - * @param language language code in string - * @return language code in integer representation - */ - static int languageToInt(String language) { - String normalized = language.toLowerCase(); - return ((normalized.charAt(0) & 0xFF) << 16) - | ((normalized.charAt(1) & 0xFF) << 8) - | (normalized.charAt(2) & 0xFF); - } } diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java index 5f2d65172180..e1bcd9952457 100644 --- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java +++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java @@ -265,7 +265,7 @@ final class HotplugDetectionAction extends HdmiCecFeatureAction { // Turn off system audio mode and update settings. tv().setSystemAudioMode(false, true); if (tv().isArcEstablished()) { - tv().setAudioReturnChannel(false); + tv().enableAudioReturnChannel(false); addAndStartAction(new RequestArcTerminationAction(localDevice(), address)); } } diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java index d80b81f6fe4a..39de8ffa2a75 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java @@ -22,8 +22,8 @@ import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDIN import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE; import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.util.Slog; - import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** @@ -62,7 +62,7 @@ public class OneTouchRecordAction extends HdmiCecFeatureAction { @Override public void onSendCompleted(int error) { // if failed to send <Record On>, display error message and finish action. - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { tv().announceOneTouchRecordResult( mRecorderAddress, ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java index fd7a7f9a887a..6893012342f9 100644 --- a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java +++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java @@ -18,10 +18,9 @@ package com.android.server.hdmi; import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN; import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.util.SparseIntArray; - import com.android.server.hdmi.HdmiControlService.SendMessageCallback; - import java.util.List; /** @@ -123,7 +122,7 @@ public class PowerStatusMonitorAction extends HdmiCecFeatureAction { public void onSendCompleted(int error) { // If fails to send <Give Device Power Status>, // update power status into UNKNOWN. - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true); } } diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java index f69f975a4b67..4eb220fd65ee 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java @@ -16,6 +16,8 @@ package com.android.server.hdmi; +import android.hardware.tv.cec.V1_0.SendMessageResult; + /** * Feature action that handles ARC action initiated by TV devices. * @@ -44,7 +46,7 @@ final class RequestArcInitiationAction extends RequestArcAction { sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { // Turn off ARC status if <Request ARC Initiation> fails. tv().setArcStatus(false); finish(); diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java index f5a01156cc92..8b5a29310233 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java @@ -16,6 +16,8 @@ package com.android.server.hdmi; +import android.hardware.tv.cec.V1_0.SendMessageResult; + /** * Feature action to handle <Request ARC Termination>. * @@ -43,7 +45,7 @@ final class RequestArcTerminationAction extends RequestArcAction { sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { // If failed to send <Request ARC Termination>, start "Disabled" ARC // transmission action. disableArcTransmission(); diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java index 9b4950b5b1ba..6633789ffc06 100644 --- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java +++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java @@ -17,6 +17,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.util.Slog; /** @@ -81,14 +82,14 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { @Override public void onSendCompleted(int error) { switch (error) { - case Constants.SEND_RESULT_SUCCESS: - case Constants.SEND_RESULT_BUSY: - case Constants.SEND_RESULT_FAILURE: + case SendMessageResult.SUCCESS: + case SendMessageResult.BUSY: + case SendMessageResult.FAIL: // The result of the command transmission, unless it is an obvious // failure indicated by the target device (or lack thereof), should // not affect the ARC status. Ignores it silently. break; - case Constants.SEND_RESULT_NAK: + case SendMessageResult.NACK: // If <Report ARC Initiated> is negatively ack'ed, disable ARC and // send <Report ARC Terminated> directly. setArcStatus(false); diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index a209cd0cca73..af1a85d31443 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -17,12 +17,12 @@ package com.android.server.hdmi; import android.annotation.Nullable; -import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.RemoteException; import android.util.Slog; - import java.util.List; /** @@ -96,7 +96,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { HdmiLogger.debug("Failed to send <System Audio Mode Request>:" + error); setSystemAudioMode(false); finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java index 78b40fd1892d..01063b757d43 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; +import android.hardware.tv.cec.V1_0.SendMessageResult; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** @@ -48,7 +49,7 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction { mAvrAddress), new SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { tv().setSystemAudioMode(false, true); finish(); } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java index 2ae5c979690d..cab8439b6f92 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java @@ -19,9 +19,9 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.RemoteException; import android.util.Slog; - import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** @@ -56,7 +56,7 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction { new SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { handleSendGiveAudioStatusFailure(); } } diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java index 16fc25fb1917..525e223b2528 100644 --- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java +++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java @@ -22,10 +22,9 @@ import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANAL import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL; import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL; +import android.hardware.tv.cec.V1_0.SendMessageResult; import android.util.Slog; - import com.android.server.hdmi.HdmiControlService.SendMessageCallback; - import java.util.Arrays; /** @@ -82,7 +81,7 @@ public class TimerRecordingAction extends HdmiCecFeatureAction { sendCommand(message, new SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error != Constants.SEND_RESULT_SUCCESS) { + if (error != SendMessageResult.SUCCESS) { tv().announceTimerRecordingResult(mRecorderAddress, TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); finish(); diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index a37dfed7c829..c99d8be230d7 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -30,7 +30,6 @@ import java.util.List; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.IUidObserver; import android.app.job.JobInfo; @@ -426,7 +425,7 @@ public final class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for package " + pkgName + " in user " + userId); } - cancelJobsForUid(pkgUid, true); + cancelJobsForUid(pkgUid); } } catch (RemoteException|IllegalArgumentException e) { /* @@ -455,7 +454,7 @@ public final class JobSchedulerService extends com.android.server.SystemService if (DEBUG) { Slog.d(TAG, "Removing jobs for uid: " + uidRemoved); } - cancelJobsForUid(uidRemoved, true); + cancelJobsForUid(uidRemoved); } } else if (Intent.ACTION_USER_REMOVED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); @@ -509,15 +508,20 @@ public final class JobSchedulerService extends com.android.server.SystemService updateUidState(uid, procState); } - @Override public void onUidGone(int uid) throws RemoteException { + @Override public void onUidGone(int uid, boolean disabled) throws RemoteException { updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + if (disabled) { + cancelJobsForUid(uid); + } } @Override public void onUidActive(int uid) throws RemoteException { } - @Override public void onUidIdle(int uid) throws RemoteException { - cancelJobsForUid(uid, false); + @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException { + if (disabled) { + cancelJobsForUid(uid); + } } }; @@ -562,7 +566,7 @@ public final class JobSchedulerService extends com.android.server.SystemService String tag) { JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag); try { - if (ActivityManagerNative.getDefault().getAppStartMode(uId, + if (ActivityManager.getService().getAppStartMode(uId, job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString() + " -- package not allowed to start"); @@ -646,26 +650,15 @@ public final class JobSchedulerService extends com.android.server.SystemService * This will remove the job from the master list, and cancel the job if it was staged for * execution or being executed. * @param uid Uid to check against for removal of a job. - * @param forceAll If true, all jobs for the uid will be canceled; if false, only those - * whose apps are stopped. + * */ - public void cancelJobsForUid(int uid, boolean forceAll) { + public void cancelJobsForUid(int uid) { List<JobStatus> jobsForUid; synchronized (mLock) { jobsForUid = mJobs.getJobsByUid(uid); } for (int i=0; i<jobsForUid.size(); i++) { JobStatus toRemove = jobsForUid.get(i); - if (!forceAll) { - String packageName = toRemove.getServiceComponent().getPackageName(); - try { - if (ActivityManagerNative.getDefault().getAppStartMode(uid, packageName) - != ActivityManager.APP_START_MODE_DISABLED) { - continue; - } - } catch (RemoteException e) { - } - } cancelJobImpl(toRemove, null); } } @@ -822,9 +815,10 @@ public final class JobSchedulerService extends com.android.server.SystemService mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE); try { - ActivityManagerNative.getDefault().registerUidObserver(mUidObserver, + ActivityManager.getService().registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE - | ActivityManager.UID_OBSERVER_IDLE, null); + | ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN, + null); } catch (RemoteException e) { // ignored; both services live in system_server } @@ -1207,7 +1201,7 @@ public final class JobSchedulerService extends com.android.server.SystemService public void process(JobStatus job) { if (isReadyToBeExecutedLocked(job)) { try { - if (ActivityManagerNative.getDefault().getAppStartMode(job.getUid(), + if (ActivityManager.getService().getAppStartMode(job.getUid(), job.getJob().getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Aborting job " + job.getUid() + ":" @@ -1381,7 +1375,7 @@ public final class JobSchedulerService extends com.android.server.SystemService int memLevel; try { - memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel(); + memLevel = ActivityManager.getService().getMemoryTrimLevel(); } catch (RemoteException e) { memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL; } @@ -1697,7 +1691,7 @@ public final class JobSchedulerService extends com.android.server.SystemService long ident = Binder.clearCallingIdentity(); try { - JobSchedulerService.this.cancelJobsForUid(uid, true); + JobSchedulerService.this.cancelJobsForUid(uid); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 5eb06ed20b42..b44087c07c16 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -17,6 +17,7 @@ package com.android.server.location; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import android.content.Context; @@ -30,6 +31,7 @@ import android.util.Log; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ILocationProvider; import com.android.internal.location.ProviderRequest; +import com.android.internal.os.TransferPipe; import com.android.server.LocationManagerService; import com.android.server.ServiceWatcher; @@ -230,14 +232,9 @@ public class LocationProviderProxy implements LocationProviderInterface { pw.flush(); try { - service.asBinder().dump(fd, args); - } catch (RemoteException e) { - pw.println("service down (RemoteException)"); - Log.w(TAG, e); - } catch (Exception e) { - pw.println("service down (Exception)"); - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); + TransferPipe.dumpAsync(service.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + pw.println("Failed to dump location provider: " + e); } } diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java index 0eb8b55e417a..8ed32f09e23a 100644 --- a/services/core/java/com/android/server/media/MediaResourceMonitorService.java +++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java @@ -17,7 +17,6 @@ package com.android.server.media; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; import android.media.IMediaResourceMonitor; @@ -84,7 +83,7 @@ public class MediaResourceMonitorService extends SystemService { private String[] getPackageNamesFromPid(int pid) { try { for (ActivityManager.RunningAppProcessInfo proc : - ActivityManagerNative.getDefault().getRunningAppProcesses()) { + ActivityManager.getService().getRunningAppProcesses()) { if (proc.pid == pid) { return proc.pkgList; } diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index 3327b36536d9..9740935ee20f 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -17,7 +17,6 @@ package com.android.server.media; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.media.session.MediaController.PlaybackInfo; import android.media.session.PlaybackState; import android.media.session.MediaSession; @@ -74,7 +73,7 @@ class MediaSessionStack { private static boolean isFromMostRecentApp(MediaSessionRecord record) { try { List<ActivityManager.RecentTaskInfo> tasks = - ActivityManagerNative.getDefault().getRecentTasks(1, + ActivityManager.getService().getRecentTasks(1, ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS | ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES | diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index d8103fc3b39e..c1506b958e83 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -612,7 +612,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { try { mActivityManager.registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE, - null); + ActivityManager.PROCESS_STATE_UNKNOWN, null); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server @@ -689,7 +689,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - @Override public void onUidGone(int uid) throws RemoteException { + @Override public void onUidGone(int uid, boolean disabled) throws RemoteException { synchronized (mUidRulesFirstLock) { removeUidStateUL(uid); } @@ -698,7 +698,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void onUidActive(int uid) throws RemoteException { } - @Override public void onUidIdle(int uid) throws RemoteException { + @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException { } }; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6ebdb3cd696b..604b3ed85e25 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -16,25 +16,24 @@ package com.android.server.notification; -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_NONE; -import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL; -import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL; -import static android.service.notification.NotificationRankerService.REASON_CHANNEL_BANNED; -import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL; -import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL; -import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK; -import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR; -import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED; -import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL; -import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL; -import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED; -import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED; -import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED; -import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF; -import static android.service.notification.NotificationRankerService.REASON_SNOOZED; -import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED; -import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED; +import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; +import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; +import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; +import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL; +import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL_ALL; +import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CLICK; +import static android.service.notification.NotificationListenerService.REASON_DELEGATE_ERROR; +import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; +import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; +import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; +import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED; +import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED; +import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED; +import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF; +import static android.service.notification.NotificationListenerService.REASON_SNOOZED; +import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; +import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; @@ -51,7 +50,6 @@ import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AutomaticZenRule; @@ -82,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; @@ -110,7 +106,7 @@ import android.service.notification.Condition; import android.service.notification.IConditionProvider; import android.service.notification.INotificationListener; import android.service.notification.IStatusBarNotificationHolder; -import android.service.notification.NotificationRankerService; +import android.service.notification.NotificationAssistantService; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationRankingUpdate; import android.service.notification.StatusBarNotification; @@ -125,7 +121,6 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; -import android.view.WindowManager; import android.view.WindowManagerInternal; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -169,12 +164,10 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.concurrent.TimeUnit; /** {@hide} */ @@ -229,7 +222,6 @@ public class NotificationManagerService extends SystemService { /** notification_enqueue status value for an ignored notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds - private String mRankerServicePackageName; private IActivityManager mAm; AudioManager mAudioManager; @@ -249,7 +241,6 @@ public class NotificationManagerService extends SystemService { private int mDefaultNotificationLedOn; private int mDefaultNotificationLedOff; - private long[] mDefaultVibrationPattern; private long[] mFallbackVibrationPattern; private boolean mUseAttentionLight; @@ -301,7 +292,7 @@ public class NotificationManagerService extends SystemService { private final UserProfiles mUserProfiles = new UserProfiles(); private NotificationListeners mListeners; - private NotificationRankers mRankerServices; + private NotificationAssistants mNotificationAssistants; private ConditionProviders mConditionProviders; private NotificationUsageStats mUsageStats; @@ -310,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; @@ -605,7 +595,7 @@ public class NotificationManagerService extends SystemService { REASON_DELEGATE_ERROR, null); long ident = Binder.clearCallingIdentity(); try { - ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, + ActivityManager.getService().crashApplication(uid, initialPid, pkg, "Bad notification posted from package " + pkg + ": " + message); } catch (RemoteException e) { @@ -758,9 +748,9 @@ public class NotificationManagerService extends SystemService { } } mListeners.onPackagesChanged(removingPackage, pkgList); - mRankerServices.onPackagesChanged(removingPackage, pkgList); + mNotificationAssistants.onPackagesChanged(removingPackage, pkgList); mConditionProviders.onPackagesChanged(removingPackage, pkgList); - mRankingHelper.onPackagesChanged(removingPackage, pkgList); + mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList); } } }; @@ -808,7 +798,7 @@ public class NotificationManagerService extends SystemService { // Refresh managed services mConditionProviders.onUserSwitched(user); mListeners.onUserSwitched(user); - mRankerServices.onUserSwitched(user); + mNotificationAssistants.onUserSwitched(user); mZenModeHelper.onUserSwitched(user); } else if (action.equals(Intent.ACTION_USER_ADDED)) { mUserProfiles.updateCache(context); @@ -819,7 +809,7 @@ public class NotificationManagerService extends SystemService { final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); mConditionProviders.onUserUnlocked(user); mListeners.onUserUnlocked(user); - mRankerServices.onUserUnlocked(user); + mNotificationAssistants.onUserUnlocked(user); mZenModeHelper.onUserUnlocked(user); } } @@ -828,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); @@ -841,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); @@ -866,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); - } } } @@ -945,8 +927,8 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting - void setSystemNotificationSound(String systemNotificationSound) { - mSystemNotificationSound = systemNotificationSound; + void setFallbackVibrationPattern(long[] vibrationPattern) { + mFallbackVibrationPattern = vibrationPattern; } @Override @@ -957,15 +939,11 @@ public class NotificationManagerService extends SystemService { Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); - // This is the package that contains the AOSP framework update. - mRankerServicePackageName = getContext().getPackageManager() - .getServicesSystemSharedLibraryPackageName(); - mHandler = new WorkerHandler(); mRankingThread.start(); String[] extractorNames; @@ -1059,10 +1037,8 @@ public class NotificationManagerService extends SystemService { // This is a MangedServices object that keeps track of the listeners. mListeners = new NotificationListeners(); - // This is a MangedServices object that keeps track of the ranker. - mRankerServices = new NotificationRankers(); - // Find the updatable ranker and register it. - mRankerServices.registerRanker(); + // This is a MangedServices object that keeps track of the assistant. + mNotificationAssistants = new NotificationAssistants(); mStatusBar = getLocalService(StatusBarManagerInternal.class); if (mStatusBar != null) { @@ -1080,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, @@ -1209,7 +1180,7 @@ public class NotificationManagerService extends SystemService { // bind to listener services. mSettingsObserver.observe(); mListeners.onBootPhaseAppsCanStart(); - mRankerServices.onBootPhaseAppsCanStart(); + mNotificationAssistants.onBootPhaseAppsCanStart(); mConditionProviders.onBootPhaseAppsCanStart(); } } @@ -1682,10 +1653,10 @@ public class NotificationManagerService extends SystemService { final StatusBarNotification sbnOut = new StatusBarNotification( sbn.getPackageName(), sbn.getOpPkg(), + sbn.getNotificationChannel(), sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), - 0, // hide score from apps sbn.getNotification().clone(), - sbn.getUser(), sbn.getPostTime()); + sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); list.add(sbnOut); } } @@ -1791,8 +1762,8 @@ public class NotificationManagerService extends SystemService { long identity = Binder.clearCallingIdentity(); try { ManagedServices manager = - mRankerServices.isComponentEnabledForCurrentProfiles(component) - ? mRankerServices + mNotificationAssistants.isComponentEnabledForCurrentProfiles(component) + ? mNotificationAssistants : mListeners; manager.setComponentState(component, true); } finally { @@ -2358,12 +2329,12 @@ public class NotificationManagerService extends SystemService { } @Override - public void applyAdjustmentFromRankerService(INotificationListener token, + public void applyAdjustmentFromAssistantService(INotificationListener token, Adjustment adjustment) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationList) { - mRankerServices.checkServiceTokenLocked(token); + mNotificationAssistants.checkServiceTokenLocked(token); applyAdjustmentLocked(adjustment); } mRankingHandler.requestSort(); @@ -2373,13 +2344,13 @@ public class NotificationManagerService extends SystemService { } @Override - public void applyAdjustmentsFromRankerService(INotificationListener token, + public void applyAdjustmentsFromAssistantService(INotificationListener token, List<Adjustment> adjustments) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationList) { - mRankerServices.checkServiceTokenLocked(token); + mNotificationAssistants.checkServiceTokenLocked(token); for (Adjustment adjustment : adjustments) { applyAdjustmentLocked(adjustment); } @@ -2478,15 +2449,14 @@ public class NotificationManagerService extends SystemService { } final StatusBarNotification summarySbn = new StatusBarNotification(adjustedSbn.getPackageName(), - adjustedSbn.getOpPkg(), Integer.MAX_VALUE, + adjustedSbn.getOpPkg(), + adjustedSbn.getNotificationChannel(), + Integer.MAX_VALUE, GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(), adjustedSbn.getInitialPid(), summaryNotification, adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY, System.currentTimeMillis()); - summaryRecord = new NotificationRecord(getContext(), summarySbn, - mRankingHelper.getNotificationChannel(adjustedSbn.getPackageName(), - adjustedSbn.getUid(), - adjustedSbn.getNotification().getNotificationChannel())); + summaryRecord = new NotificationRecord(getContext(), summarySbn); summaries.put(pkg, summarySbn.getKey()); } } @@ -2632,9 +2602,8 @@ public class NotificationManagerService extends SystemService { } } pw.println(')'); - pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName); - pw.println("\n Notification ranker services:"); - mRankerServices.dump(pw, filter); + pw.println("\n Notification assistant services:"); + mNotificationAssistants.dump(pw, filter); } if (!zenOnly) { @@ -2734,9 +2703,11 @@ public class NotificationManagerService extends SystemService { throw new IllegalArgumentException("null not allowed: pkg=" + pkg + " id=" + id + " notification=" + notification); } + final NotificationChannel channel = mRankingHelper.getNotificationChannelWithFallback(pkg, + callingUid, notification.getChannel()); final StatusBarNotification n = new StatusBarNotification( - pkg, opPkg, id, tag, callingUid, callingPid, 0, notification, - user); + pkg, opPkg, channel, id, tag, callingUid, callingPid, notification, + user, null, System.currentTimeMillis()); // Limit the number of notifications that any given package except the android // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. @@ -2799,9 +2770,7 @@ public class NotificationManagerService extends SystemService { Notification.PRIORITY_MAX); // setup local book-keeping - final NotificationRecord r = new NotificationRecord(getContext(), n, - mRankingHelper.getNotificationChannelWithFallback(pkg, callingUid, - n.getNotification().getNotificationChannel())); + final NotificationRecord r = new NotificationRecord(getContext(), n); mHandler.post(new EnqueueNotificationRunnable(userId, r)); idOut[0] = id; @@ -2885,9 +2854,9 @@ public class NotificationManagerService extends SystemService { } } - // tell the ranker service about the notification - if (mRankerServices.isEnabled()) { - mRankerServices.onNotificationEnqueued(r); + // tell the assistant service about the notification + if (mNotificationAssistants.isEnabled()) { + mNotificationAssistants.onNotificationEnqueued(r); // TODO delay the code below here for 100ms or until there is an answer } @@ -2930,7 +2899,8 @@ public class NotificationManagerService extends SystemService { } else { Slog.e(TAG, "Not posting notification without small icon: " + notification); if (old != null && !old.isCanceled) { - mListeners.notifyRemovedLocked(n); + mListeners.notifyRemovedLocked(n, + NotificationListenerService.REASON_DELEGATE_ERROR); mHandler.post(new Runnable() { @Override public void run() { @@ -3047,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. @@ -3091,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 @@ -3181,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) { @@ -3542,7 +3450,7 @@ public class NotificationManagerService extends SystemService { // status bar if (r.getNotification().getSmallIcon() != null) { r.isCanceled = true; - mListeners.notifyRemovedLocked(r.sbn); + mListeners.notifyRemovedLocked(r.sbn, reason); mHandler.post(new Runnable() { @Override public void run() { @@ -4075,19 +3983,19 @@ public class NotificationManagerService extends SystemService { } } - public class NotificationRankers extends ManagedServices { + public class NotificationAssistants extends ManagedServices { - public NotificationRankers() { + public NotificationAssistants() { super(getContext(), mHandler, mNotificationList, mUserProfiles); } @Override protected Config getConfig() { Config c = new Config(); - c.caption = "notification ranker service"; - c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE; - c.secureSettingName = null; - c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE; + c.caption = "notification assistant service"; + c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; + c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; + c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; c.clientLabel = R.string.notification_ranker_binding_label; return c; @@ -4117,10 +4025,10 @@ public class NotificationManagerService extends SystemService { final StatusBarNotification sbn = r.sbn; TrimCache trimCache = new TrimCache(sbn); - // mServices is the list inside ManagedServices of all the rankers, + // mServices is the list inside ManagedServices of all the assistants, // There should be only one, but it's a list, so while we enforce // singularity elsewhere, we keep it general here, to avoid surprises. - for (final ManagedServiceInfo info : NotificationRankers.this.mServices) { + for (final ManagedServiceInfo info : NotificationAssistants.this.mServices) { boolean sbnVisible = isVisibleToListener(sbn, info); if (!sbnVisible) { continue; @@ -4140,68 +4048,18 @@ public class NotificationManagerService extends SystemService { private void notifyEnqueued(final ManagedServiceInfo info, final StatusBarNotification sbn, int importance, boolean fromUser) { - final INotificationListener ranker = (INotificationListener) info.service; + final INotificationListener assistant = (INotificationListener) info.service; StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); try { - ranker.onNotificationEnqueued(sbnHolder, importance, fromUser); + assistant.onNotificationEnqueued(sbnHolder, importance, fromUser); } catch (RemoteException ex) { - Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex); + Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); } } public boolean isEnabled() { return !mServices.isEmpty(); } - - @Override - public void onUserSwitched(int user) { - synchronized (mNotificationList) { - int i = mServices.size()-1; - while (i --> 0) { - final ManagedServiceInfo info = mServices.get(i); - unregisterService(info.service, info.userid); - } - } - registerRanker(); - } - - @Override - public void onPackagesChanged(boolean removingPackage, String[] pkgList) { - if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage - + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))); - if (mRankerServicePackageName == null) { - return; - } - - if (pkgList != null && (pkgList.length > 0) && !removingPackage) { - for (String pkgName : pkgList) { - if (mRankerServicePackageName.equals(pkgName)) { - registerRanker(); - } - } - } - } - - protected void registerRanker() { - // Find the updatable ranker and register it. - if (mRankerServicePackageName == null) { - Slog.w(TAG, "could not start ranker service: no package specified!"); - return; - } - Set<ComponentName> rankerComponents = queryPackageForServices( - mRankerServicePackageName, UserHandle.USER_SYSTEM); - Iterator<ComponentName> iterator = rankerComponents.iterator(); - if (iterator.hasNext()) { - ComponentName rankerComponent = iterator.next(); - if (iterator.hasNext()) { - Slog.e(TAG, "found multiple ranker services:" + rankerComponents); - } else { - registerSystemService(rankerComponent, UserHandle.USER_SYSTEM); - } - } else { - Slog.w(TAG, "could not start ranker service: none found"); - } - } } public class NotificationListeners extends ManagedServices { @@ -4295,7 +4153,7 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyRemoved(info, oldSbnLightClone, update); + notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED); } }); continue; @@ -4314,7 +4172,7 @@ public class NotificationManagerService extends SystemService { /** * asynchronously notify all listeners about a removed notification */ - public void notifyRemovedLocked(StatusBarNotification sbn) { + public void notifyRemovedLocked(StatusBarNotification sbn, int reason) { // make a copy in case changes are made to the underlying Notification object // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the // notification @@ -4327,7 +4185,7 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - notifyRemoved(info, sbnLight, update); + notifyRemoved(info, sbnLight, update, reason); } }); } @@ -4391,14 +4249,14 @@ public class NotificationManagerService extends SystemService { } private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, - NotificationRankingUpdate rankingUpdate) { + NotificationRankingUpdate rankingUpdate, int reason) { if (!info.enabledAndUserMatches(sbn.getUserId())) { return; } final INotificationListener listener = (INotificationListener) info.service; StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); try { - listener.onNotificationRemoved(sbnHolder, rankingUpdate); + listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (removed): " + listener, ex); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index a1256db61cba..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,12 +106,13 @@ public final class NotificationRecord { private int mSuppressedVisualEffects = 0; private String mUserExplanation; private String mPeopleExplanation; - - private NotificationChannel mNotificationChannel; + private boolean mPreChannelsNotification = true; + private Uri mSound; + private long[] mVibration; + private AudioAttributes mAttributes; @VisibleForTesting - public NotificationRecord(Context context, StatusBarNotification sbn, - NotificationChannel channel) + public NotificationRecord(Context context, StatusBarNotification sbn) { this.sbn = sbn; mOriginalFlags = sbn.getNotification().flags; @@ -114,13 +121,95 @@ public final class NotificationRecord { mUpdateTimeMs = mCreationTimeMs; mContext = context; stats = new NotificationUsageStats.SingleNotificationStats(); - mNotificationChannel = channel; - 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(); - int importance = IMPORTANCE_DEFAULT; + + 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 = getChannel().getImportance(); + int requestedImportance = IMPORTANCE_DEFAULT; // Migrate notification flags to scores if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) { @@ -129,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 - || mNotificationChannel.shouldVibrate() - || mNotificationChannel.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; @@ -287,7 +374,10 @@ public final class NotificationRecord { pw.println(prefix + " mVisibleSinceMs=" + mVisibleSinceMs); pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs); pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects); - pw.println(prefix + " mNotificationChannel= " + mNotificationChannel); + pw.println(prefix + " notificationChannel= " + notification.getChannel()); + pw.println(prefix + " mSound= " + mSound); + pw.println(prefix + " mVibration= " + mVibration); + pw.println(prefix + " mAttributes= " + mAttributes); } @@ -366,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; } @@ -535,6 +625,18 @@ public final class NotificationRecord { } public NotificationChannel getChannel() { - return mNotificationChannel; + 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 1bb8b3bcd326..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()); @@ -716,9 +716,8 @@ public class RankingHelper implements RankingConfig { return packageBans; } - public void onPackagesChanged(boolean removingPackage, String[] pkgList) { - if (removingPackage || pkgList == null || pkgList.length == 0 - || mRestoredWithoutUids.isEmpty()) { + public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList) { + if (removingPackage || pkgList == null || pkgList.length == 0) { return; // nothing to do } boolean updated = false; @@ -726,8 +725,7 @@ public class RankingHelper implements RankingConfig { final Record r = mRestoredWithoutUids.get(pkg); if (r != null) { try { - //TODO: http://b/22388012 - r.uid = mPm.getPackageUidAsUser(r.pkg, UserHandle.USER_SYSTEM); + r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId); mRestoredWithoutUids.remove(pkg); mRecords.put(recordKey(r.pkg, r.uid), r); updated = true; @@ -737,7 +735,7 @@ public class RankingHelper implements RankingConfig { } try { Record fullRecord = getRecord(pkg, - mPm.getPackageUidAsUser(pkg, UserHandle.USER_SYSTEM)); + mPm.getPackageUidAsUser(pkg, changeUserId)); if (fullRecord != null) { clampDefaultChannel(fullRecord); } diff --git a/services/core/java/com/android/server/pm/EphemeralResolver.java b/services/core/java/com/android/server/pm/EphemeralResolver.java new file mode 100644 index 000000000000..7ddd058b4e5a --- /dev/null +++ b/services/core/java/com/android/server/pm/EphemeralResolver.java @@ -0,0 +1,250 @@ +/* + * 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.pm; + +import android.app.ActivityManager; +import android.app.ActivityManagerNative; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.IIntentSender; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.IntentSender; +import android.content.pm.ActivityInfo; +import android.content.pm.EphemeralIntentFilter; +import android.content.pm.EphemeralRequest; +import android.content.pm.EphemeralResolveInfo; +import android.content.pm.EphemeralResponse; +import android.content.pm.EphemeralResolveInfo.EphemeralDigest; +import android.os.Binder; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; +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; + +/** @hide */ +public abstract class EphemeralResolver { + + /** TODO b/30204367 remove when the platform fully supports ephemeral applications */ + public static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false; + + public static EphemeralResponse doEphemeralResolutionPhaseOne(Context context, + EphemeralResolverConnection connection, EphemeralRequest requestObj) { + final Intent intent = requestObj.origIntent; + final EphemeralDigest digest = + new EphemeralDigest(intent.getData().getHost(), 5 /*maxDigests*/); + final int[] shaPrefix = digest.getDigestPrefix(); + final List<EphemeralResolveInfo> ephemeralResolveInfoList = + connection.getEphemeralResolveInfoList(shaPrefix); + if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) { + // No hash prefix match; there are no ephemeral apps for this domain. + return null; + } + + final String token = UUID.randomUUID().toString(); + return EphemeralResolver.filterEphemeralIntent(ephemeralResolveInfoList, + intent, requestObj.resolvedType, requestObj.userId, + intent.getPackage(), digest, token); + } + + public static void doEphemeralResolutionPhaseTwo(Context context, + EphemeralResolverConnection connection, EphemeralRequest requestObj, + ActivityInfo ephemeralInstaller, Handler callbackHandler) { + final Intent intent = requestObj.origIntent; + final String hostName = intent.getData().getHost(); + final EphemeralDigest digest = new EphemeralDigest(hostName, 5 /*maxDigests*/); + + final PhaseTwoCallback callback = new PhaseTwoCallback() { + @Override + void onPhaseTwoResolved(EphemeralResolveInfo ephemeralResolveInfo, + int sequence) { + final String packageName; + final String splitName; + if (ephemeralResolveInfo != null) { + final ArrayList<EphemeralResolveInfo> ephemeralResolveInfoList = + new ArrayList<EphemeralResolveInfo>(1); + ephemeralResolveInfoList.add(ephemeralResolveInfo); + final EphemeralResponse ephemeralIntentInfo = + EphemeralResolver.filterEphemeralIntent( + ephemeralResolveInfoList, intent, null /*resolvedType*/, + 0 /*userId*/, intent.getPackage(), digest, + requestObj.responseObj.token); + if (ephemeralIntentInfo != null + && ephemeralIntentInfo.resolveInfo != null) { + packageName = ephemeralIntentInfo.resolveInfo.getPackageName(); + splitName = ephemeralIntentInfo.splitName; + } else { + packageName = null; + splitName = null; + } + } else { + packageName = null; + splitName = null; + } + final Intent installerIntent = buildEphemeralInstallerIntent( + requestObj.launchIntent, + requestObj.origIntent, + requestObj.callingPackage, + requestObj.resolvedType, + requestObj.userId, + packageName, + splitName, + requestObj.responseObj.token, + false /*needsPhaseTwo*/); + installerIntent.setComponent(new ComponentName( + ephemeralInstaller.packageName, ephemeralInstaller.name)); + context.startActivity(installerIntent); + } + }; + connection.getEphemeralIntentFilterList( + hostName, callback, callbackHandler, 0 /*sequence*/); + } + + /** + * Builds and returns an intent to launch the ephemeral installer. + */ + public static Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent, + String callingPackage, String resolvedType, int userId, String ephemeralPackageName, + String ephemeralSplitName, String token, boolean needsPhaseTwo) { + // Construct the intent that launches the ephemeral installer + int flags = launchIntent.getFlags(); + final Intent intent = new Intent(); + intent.setFlags(flags + | Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NO_HISTORY + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + // TODO: Remove when the platform has fully implemented ephemeral apps + intent.setData(origIntent.getData().buildUpon().clearQuery().build()); + intent.putExtra(Intent.EXTRA_EPHEMERAL_TOKEN, token); + intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost()); + + if (!needsPhaseTwo) { + // We have all of the data we need; just start the installer without a second phase + final Intent nonEphemeralIntent = new Intent(origIntent); + nonEphemeralIntent.setFlags( + nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL); + // Intent that is launched if the ephemeral package couldn't be installed + // for any reason. + try { + final IIntentSender failureIntentTarget = ActivityManagerNative.getDefault() + .getIntentSender( + ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, + null /*token*/, null /*resultWho*/, 1 /*requestCode*/, + new Intent[] { nonEphemeralIntent }, + new String[] { resolvedType }, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE, + null /*bOptions*/, userId); + intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, + new IntentSender(failureIntentTarget)); + } catch (RemoteException ignore) { /* ignore; same process */ } + + final Intent ephemeralIntent; + if (EphemeralResolver.USE_DEFAULT_EPHEMERAL_LAUNCHER) { + // Force the intent to be directed to the ephemeral package + ephemeralIntent = new Intent(origIntent); + ephemeralIntent.setPackage(ephemeralPackageName); + } else { + // Success intent goes back to the installer + ephemeralIntent = new Intent(launchIntent); + } + + // Intent that is eventually launched if the ephemeral package was + // installed successfully. This will actually be launched by a platform + // broadcast receiver. + try { + final IIntentSender successIntentTarget = ActivityManagerNative.getDefault() + .getIntentSender( + ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, + null /*token*/, null /*resultWho*/, 0 /*requestCode*/, + new Intent[] { ephemeralIntent }, + new String[] { resolvedType }, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE, + null /*bOptions*/, userId); + intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, + new IntentSender(successIntentTarget)); + } catch (RemoteException ignore) { /* ignore; same process */ } + + intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackageName); + intent.putExtra(Intent.EXTRA_SPLIT_NAME, ephemeralSplitName); + } + + return intent; + } + + private static EphemeralResponse filterEphemeralIntent( + List<EphemeralResolveInfo> ephemeralResolveInfoList, + Intent intent, String resolvedType, int userId, String packageName, + EphemeralDigest digest, String token) { + final int[] shaPrefix = digest.getDigestPrefix(); + final byte[][] digestBytes = digest.getDigestBytes(); + // Go in reverse order so we match the narrowest scope first. + for (int i = shaPrefix.length - 1; i >= 0 ; --i) { + for (EphemeralResolveInfo ephemeralInfo : ephemeralResolveInfoList) { + if (!Arrays.equals(digestBytes[i], ephemeralInfo.getDigestBytes())) { + continue; + } + if (packageName != null + && !packageName.equals(ephemeralInfo.getPackageName())) { + continue; + } + final List<EphemeralIntentFilter> ephemeralFilters = + ephemeralInfo.getIntentFilters(); + // No filters; we need to start phase two + if (ephemeralFilters == null || ephemeralFilters.isEmpty()) { + return new EphemeralResponse(ephemeralInfo, + new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/, + null /*splitName*/, token, true /*needsPhase2*/); + } + // We have a domain match; resolve the filters to see if anything matches. + final PackageManagerService.EphemeralIntentResolver ephemeralResolver = + new PackageManagerService.EphemeralIntentResolver(); + for (int j = ephemeralFilters.size() - 1; j >= 0; --j) { + final EphemeralIntentFilter ephemeralFilter = ephemeralFilters.get(j); + final List<IntentFilter> splitFilters = ephemeralFilter.getFilters(); + if (splitFilters == null || splitFilters.isEmpty()) { + continue; + } + for (int k = splitFilters.size() - 1; k >= 0; --k) { + final EphemeralResponse intentInfo = + new EphemeralResponse(ephemeralInfo, + splitFilters.get(k), ephemeralFilter.getSplitName(), + token, false /*needsPhase2*/); + ephemeralResolver.addFilter(intentInfo); + } + } + List<EphemeralResponse> matchedResolveInfoList = ephemeralResolver + .queryIntent(intent, resolvedType, false /*defaultOnly*/, userId); + if (!matchedResolveInfoList.isEmpty()) { + return matchedResolveInfoList.get(0); + } + } + } + // Hash or filter mis-match; no ephemeral apps for this domain. + return null; + } +} diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java index a6a377419a6a..2b6ce10741c4 100644 --- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java +++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java @@ -23,8 +23,10 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.EphemeralResolveInfo; +import android.content.pm.EphemeralResponse; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; @@ -32,7 +34,10 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.TimedRemoteCaller; +import com.android.internal.os.TransferPipe; + import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -64,12 +69,11 @@ final class EphemeralResolverConnection { mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName); } - public final List<EphemeralResolveInfo> getEphemeralResolveInfoList( - int hashPrefix[], int prefixMask) { + public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(int hashPrefix[]) { throwIfCalledOnMainThread(); try { return mGetEphemeralResolveInfoCaller.getEphemeralResolveInfoList( - getRemoteInstanceLazy(), hashPrefix, prefixMask); + getRemoteInstanceLazy(), hashPrefix); } catch (RemoteException re) { } catch (TimeoutException te) { } finally { @@ -80,19 +84,40 @@ final class EphemeralResolverConnection { return null; } + 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 EphemeralResolveInfo ephemeralResolveInfo = + data.getParcelable(EphemeralResolverService.EXTRA_RESOLVE_INFO); + callbackHandler.post(new Runnable() { + @Override + public void run() { + callback.onPhaseTwoResolved(ephemeralResolveInfo, sequence); + } + }); + } + }; + try { + getRemoteInstanceLazy() + .getEphemeralIntentFilterList(remoteCallback, hostName, sequence); + } catch (RemoteException re) { + } catch (TimeoutException te) { + } + } + public void dump(FileDescriptor fd, PrintWriter pw, String prefix) { synchronized (mLock) { pw.append(prefix).append("bound=") .append((mRemoteInstance != null) ? "true" : "false").println(); pw.flush(); - try { - getRemoteInstanceLazy().asBinder().dump(fd, new String[] { prefix }); - } catch (TimeoutException te) { - /* ignore */ - } catch (RemoteException re) { - /* ignore */ + TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd, + new String[] { prefix }); + } catch (IOException | TimeoutException | RemoteException e) { + pw.println("Failed to dump remote instance: " + e); } } } @@ -144,6 +169,13 @@ final class EphemeralResolverConnection { } } + /** + * Asynchronous callback when results come back from ephemeral resolution phase two. + */ + public abstract static class PhaseTwoCallback { + abstract void onPhaseTwoResolved(EphemeralResolveInfo ephemeralResolveInfo, int sequence); + } + private final class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -181,10 +213,10 @@ final class EphemeralResolverConnection { } public List<EphemeralResolveInfo> getEphemeralResolveInfoList( - IEphemeralResolver target, int hashPrefix[], int prefixMask) + IEphemeralResolver target, int hashPrefix[]) throws RemoteException, TimeoutException { final int sequence = onBeforeRemoteCall(); - target.getEphemeralResolveInfoList(mCallback, hashPrefix, prefixMask, sequence); + target.getEphemeralResolveInfoList(mCallback, hashPrefix, sequence); return getResultTimed(sequence); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca773357c772..ee3f42b7808e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -101,7 +101,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.ResourcesManager; import android.app.admin.IDevicePolicyManager; @@ -122,9 +121,9 @@ import android.content.pm.ApplicationInfo; import android.content.pm.AppsQueryHelper; import android.content.pm.ComponentInfo; import android.content.pm.EphemeralApplicationInfo; +import android.content.pm.EphemeralRequest; import android.content.pm.EphemeralResolveInfo; -import android.content.pm.EphemeralResolveInfo.EphemeralDigest; -import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo; +import android.content.pm.EphemeralResponse; import android.content.pm.FeatureInfo; import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IPackageDataObserver; @@ -192,8 +191,8 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; -import android.os.storage.IMountService; -import android.os.storage.MountServiceInternal; +import android.os.storage.IStorageManager; +import android.os.storage.StorageManagerInternal; import android.os.storage.StorageEventListener; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; @@ -208,6 +207,7 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Base64; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.ExceptionUtils; @@ -233,6 +233,7 @@ import com.android.internal.content.PackageHelper; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.os.InstallerConnection.InstallerException; +import com.android.internal.os.RoSystemProperties; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; import com.android.internal.telephony.CarrierAppUtils; @@ -285,6 +286,7 @@ import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; @@ -336,7 +338,7 @@ import java.util.concurrent.atomic.AtomicInteger; * * <pre> * $ runtest -c android.content.pm.PackageManagerTests frameworks-core - * $ cts-tradefed run commandAndExit cts -m AppSecurityTests + * $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases * </pre> */ public class PackageManagerService extends IPackageManager.Stub { @@ -471,9 +473,12 @@ public class PackageManagerService extends IPackageManager.Stub { * VENDOR_OVERLAY_DIR. */ private static final String VENDOR_OVERLAY_THEME_PROPERTY = "ro.boot.vendor.overlay.theme"; - - private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000; - private static int DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT = 5; + /** + * Same as VENDOR_OVERLAY_THEME_PROPERTY, except persistent. If set will override whatever + * is in VENDOR_OVERLAY_THEME_PROPERTY. + */ + private static final String VENDOR_OVERLAY_THEME_PERSIST_PROPERTY + = "persist.vendor.overlay.theme"; /** Permission grant: not grant the permission. */ private static final int GRANT_DENIED = 1; @@ -1063,6 +1068,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final int START_INTENT_FILTER_VERIFICATIONS = 17; static final int INTENT_FILTER_VERIFIED = 18; static final int WRITE_PACKAGE_LIST = 19; + static final int EPHEMERAL_RESOLUTION_PHASE_TWO = 20; static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds @@ -1079,8 +1085,8 @@ public class PackageManagerService extends IPackageManager.Stub { class DefaultContainerConnection implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected"); - IMediaContainerService imcs = - IMediaContainerService.Stub.asInterface(service); + final IMediaContainerService imcs = IMediaContainerService.Stub + .asInterface(Binder.allowBlocking(service)); mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); } @@ -1466,10 +1472,11 @@ public class PackageManagerService extends IPackageManager.Stub { } if (reportStatus) { try { - if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back"); - PackageHelper.getMountService().finishMediaUpdate(); + if (DEBUG_SD_INSTALL) Log.i(TAG, + "Invoking StorageManagerService call back"); + PackageHelper.getStorageManager().finishMediaUpdate(); } catch (RemoteException e) { - Log.e(TAG, "MountService not running?"); + Log.e(TAG, "StorageManagerService not running?"); } } } break; @@ -1632,6 +1639,13 @@ public class PackageManagerService extends IPackageManager.Stub { break; } + case EPHEMERAL_RESOLUTION_PHASE_TWO: { + EphemeralResolver.doEphemeralResolutionPhaseTwo(mContext, + mEphemeralResolverConnection, + (EphemeralRequest) msg.obj, + mEphemeralInstallerActivity, + mHandler); + } } } } @@ -1874,6 +1888,11 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten"); deletePackage(ps.name, new LegacyPackageDeleteObserver(null).getBinder(), UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS); + + // Try very hard to release any references to this package + // so we don't risk the system server being killed due to + // open FDs + AttributeCache.instance().removePackage(ps.name); } mSettings.onVolumeForgotten(fsUuid); @@ -2289,7 +2308,10 @@ public class PackageManagerService extends IPackageManager.Stub { // Collect vendor overlay packages. (Do this before scanning any apps.) // For security and version matching reason, only consider // overlay packages if they reside in the right directory. - String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY); + String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PERSIST_PROPERTY); + if (overlayThemeDir.isEmpty()) { + overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY); + } if (!overlayThemeDir.isEmpty()) { scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlayThemeDir), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM @@ -4126,9 +4148,9 @@ public class PackageManagerService extends IPackageManager.Stub { final long token = Binder.clearCallingIdentity(); try { if (sUserManager.isInitialized(userId)) { - MountServiceInternal mountServiceInternal = LocalServices.getService( - MountServiceInternal.class); - mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName); + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName); } } finally { Binder.restoreCallingIdentity(token); @@ -4529,7 +4551,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void killUid(int appId, int userId, String reason) { final long identity = Binder.clearCallingIdentity(); try { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (am != null) { try { am.killUid(appId, userId, reason); @@ -4936,55 +4958,13 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } - private static EphemeralResolveInfo getEphemeralResolveInfo( - Context context, EphemeralResolverConnection resolverConnection, Intent intent, - String resolvedType, int userId, String packageName) { - final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(), - Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK); - final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(), - Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT); - final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask, - ephemeralPrefixCount); - final int[] shaPrefix = digest.getDigestPrefix(); - final byte[][] digestBytes = digest.getDigestBytes(); - final List<EphemeralResolveInfo> ephemeralResolveInfoList = - resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask); - if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) { - // No hash prefix match; there are no ephemeral apps for this domain. - return null; - } - - // Go in reverse order so we match the narrowest scope first. - for (int i = shaPrefix.length - 1; i >= 0 ; --i) { - for (EphemeralResolveInfo ephemeralApplication : ephemeralResolveInfoList) { - if (!Arrays.equals(digestBytes[i], ephemeralApplication.getDigestBytes())) { - continue; - } - final List<IntentFilter> filters = ephemeralApplication.getFilters(); - // No filters; this should never happen. - if (filters.isEmpty()) { - continue; - } - if (packageName != null - && !packageName.equals(ephemeralApplication.getPackageName())) { - continue; - } - // We have a domain match; resolve the filters to see if anything matches. - final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver(); - for (int j = filters.size() - 1; j >= 0; --j) { - final EphemeralResolveIntentInfo intentInfo = - new EphemeralResolveIntentInfo(filters.get(j), ephemeralApplication); - ephemeralResolver.addFilter(intentInfo); - } - List<EphemeralResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent( - intent, resolvedType, false /*defaultOnly*/, userId); - if (!matchedResolveInfoList.isEmpty()) { - return matchedResolveInfoList.get(0); - } - } - } - // Hash or filter mis-match; no ephemeral apps for this domain. - return null; + private void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj, + Intent origIntent, String resolvedType, Intent launchIntent, String callingPackage, + int userId) { + final Message msg = mHandler.obtainMessage(EPHEMERAL_RESOLUTION_PHASE_TWO, + new EphemeralRequest(responseObj, origIntent, resolvedType, launchIntent, + callingPackage, userId)); + mHandler.sendMessage(msg); } private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, @@ -5460,15 +5440,17 @@ public class PackageManagerService extends IPackageManager.Stub { } if (addEphemeral) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); - final EphemeralResolveInfo ai = getEphemeralResolveInfo( - mContext, mEphemeralResolverConnection, intent, resolvedType, userId, - matchEphemeralPackage ? pkgName : null); - if (ai != null) { + final EphemeralRequest requestObject = new EphemeralRequest( + null /*responseObj*/, intent /*origIntent*/, resolvedType, + null /*launchIntent*/, null /*callingPackage*/, userId); + final EphemeralResponse intentInfo = EphemeralResolver.doEphemeralResolutionPhaseOne( + mContext, mEphemeralResolverConnection, requestObject); + if (intentInfo != null) { if (DEBUG_EPHEMERAL) { Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list"); } final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo); - ephemeralInstaller.ephemeralResolveInfo = ai; + ephemeralInstaller.ephemeralResponse = intentInfo; // make sure this resolver is the default ephemeralInstaller.isDefault = true; ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART @@ -7226,15 +7208,15 @@ public class PackageManagerService extends IPackageManager.Stub { // Before everything else, see whether we need to fstrim. try { - IMountService ms = PackageHelper.getMountService(); - if (ms != null) { + IStorageManager sm = PackageHelper.getStorageManager(); + if (sm != null) { boolean doTrim = false; final long interval = android.provider.Settings.Global.getLong( mContext.getContentResolver(), android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL, DEFAULT_MANDATORY_FSTRIM_INTERVAL); if (interval > 0) { - final long timeSinceLast = System.currentTimeMillis() - ms.lastMaintenance(); + final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance(); if (timeSinceLast > interval) { doTrim = true; Slog.w(TAG, "No disk maintenance in " + timeSinceLast @@ -7248,19 +7230,19 @@ public class PackageManagerService extends IPackageManager.Stub { } if (!isFirstBoot() && dexOptDialogShown) { try { - ActivityManagerNative.getDefault().showBootMessage( + ActivityManager.getService().showBootMessage( mContext.getResources().getString( R.string.android_upgrading_fstrim), true); } catch (RemoteException e) { } } - ms.runMaintenance(); + sm.runMaintenance(); } } else { - Slog.e(TAG, "Mount service unavailable!"); + Slog.e(TAG, "storageManager service unavailable!"); } } catch (RemoteException e) { - // Can't happen; MountService is local + // Can't happen; StorageManagerService is local } } @@ -7335,7 +7317,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (showDialog) { try { - ActivityManagerNative.getDefault().showBootMessage( + ActivityManager.getService().showBootMessage( mContext.getResources().getString(R.string.android_upgrading_apk, numberOfPackagesVisited, numberOfPackagesToDexopt), true); } catch (RemoteException e) { @@ -9683,7 +9665,7 @@ public class PackageManagerService extends IPackageManager.Stub { // version of the application while the new one gets installed. final long token = Binder.clearCallingIdentity(); try { - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (am != null) { try { am.killApplication(pkgName, appId, userId, reason); @@ -10383,14 +10365,28 @@ public class PackageManagerService extends IPackageManager.Stub { private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, BasePermission bp, PermissionsState origPermissions) { - boolean allowed; - allowed = (compareSignatures( + boolean privilegedPermission = (bp.protectionLevel + & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0; + boolean controlPrivappPermissions = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS; + boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage); + boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName); + if (controlPrivappPermissions && privilegedPermission && pkg.isPrivilegedApp() + && !platformPackage && platformPermission) { + ArraySet<String> wlPermissions = SystemConfig.getInstance() + .getPrivAppPermissions(pkg.packageName); + boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); + if (!whitelisted) { + // Log for now. TODO Enforce permissions + Slog.w(TAG, "Privileged permission " + perm + " for package " + + pkg.packageName + " - not in privapp-permissions whitelist"); + } + } + boolean allowed = (compareSignatures( bp.packageSetting.signatures.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH) || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH); - if (!allowed && (bp.protectionLevel - & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) { + if (!allowed && privilegedPermission) { if (isSystemApp(pkg)) { // For updated system applications, a system permission // is granted only if it had been defined by the original application. @@ -11441,8 +11437,8 @@ public class PackageManagerService extends IPackageManager.Stub { private int mFlags; } - private static final class EphemeralIntentResolver - extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> { + static final class EphemeralIntentResolver + extends IntentResolver<EphemeralResponse, EphemeralResponse> { /** * The result that has the highest defined order. Ordering applies on a * per-package basis. Mapping is from package name to Pair of order and @@ -11457,46 +11453,46 @@ public class PackageManagerService extends IPackageManager.Stub { final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>(); @Override - protected EphemeralResolveIntentInfo[] newArray(int size) { - return new EphemeralResolveIntentInfo[size]; + protected EphemeralResponse[] newArray(int size) { + return new EphemeralResponse[size]; } @Override - protected boolean isPackageForFilter(String packageName, EphemeralResolveIntentInfo info) { + protected boolean isPackageForFilter(String packageName, EphemeralResponse responseObj) { return true; } @Override - protected EphemeralResolveInfo newResult(EphemeralResolveIntentInfo info, int match, + protected EphemeralResponse newResult(EphemeralResponse responseObj, int match, int userId) { if (!sUserManager.exists(userId)) { return null; } - final String packageName = info.getEphemeralResolveInfo().getPackageName(); - final Integer order = info.getOrder(); + final String packageName = responseObj.resolveInfo.getPackageName(); + final Integer order = responseObj.getOrder(); final Pair<Integer, EphemeralResolveInfo> lastOrderResult = mOrderResult.get(packageName); // ordering is enabled and this item's order isn't high enough if (lastOrderResult != null && lastOrderResult.first >= order) { return null; } - final EphemeralResolveInfo res = info.getEphemeralResolveInfo(); + final EphemeralResolveInfo res = responseObj.resolveInfo; if (order > 0) { // non-zero order, enable ordering mOrderResult.put(packageName, new Pair<>(order, res)); } - return res; + return responseObj; } @Override - protected void filterResults(List<EphemeralResolveInfo> results) { + protected void filterResults(List<EphemeralResponse> results) { // only do work if ordering is enabled [most of the time it won't be] if (mOrderResult.size() == 0) { return; } int resultSize = results.size(); for (int i = 0; i < resultSize; i++) { - final EphemeralResolveInfo info = results.get(i); + final EphemeralResolveInfo info = results.get(i).resolveInfo; final String packageName = info.getPackageName(); final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName); if (savedInfo == null) { @@ -11575,7 +11571,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void run() { try { - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); if (am == null) return; final int[] resolvedUserIds; if (userIds == null) { @@ -11672,7 +11668,7 @@ public class PackageManagerService extends IPackageManager.Stub { } Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE); intent.setComponent(DEFAULT_CONTAINER_COMPONENT); - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); if (am != null) { try { am.startService(null, intent, null, mContext.getOpPackageName(), @@ -11822,7 +11818,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (!mUserManagerInternal.isUserRunning(userId)) { return; } - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); try { // Deliver LOCKED_BOOT_COMPLETED first Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) @@ -13784,7 +13780,7 @@ public class PackageManagerService extends IPackageManager.Stub { } /** - * Extract the MountService "container ID" from the full code path of an + * Extract the StorageManagerService "container ID" from the full code path of an * .apk. */ static String cidFromCodePath(String fullCodePath) { @@ -14249,11 +14245,13 @@ public class PackageManagerService extends IPackageManager.Stub { } private File getNextCodePath(File targetDir, String packageName) { - int suffix = 1; File result; + SecureRandom random = new SecureRandom(); + byte[] bytes = new byte[16]; do { + random.nextBytes(bytes); + String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); result = new File(targetDir, packageName + "-" + suffix); - suffix++; } while (result.exists()); return result; } @@ -16615,7 +16613,8 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (this) { - mContainerService = IMediaContainerService.Stub.asInterface(service); + mContainerService = IMediaContainerService.Stub + .asInterface(Binder.allowBlocking(service)); notifyAll(); } } @@ -17112,7 +17111,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void postPreferredActivityChangedBroadcast(int userId) { mHandler.post(() -> { - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); if (am == null) { return; } @@ -18088,8 +18087,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } synchronized (mPackages) { - if (uid == Process.SHELL_UID) { + if (uid == Process.SHELL_UID + && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { // Shell can only change whole packages between ENABLED and DISABLED_USER states + // unless it is a test package. int oldState = pkgSetting.getEnabled(userId); if (className == null && @@ -18382,10 +18383,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); mInstallerService.systemReady(); mPackageDexOptimizer.systemReady(); - MountServiceInternal mountServiceInternal = LocalServices.getService( - MountServiceInternal.class); - mountServiceInternal.addExternalStoragePolicy( - new MountServiceInternal.ExternalStorageMountPolicy() { + StorageManagerInternal StorageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + StorageManagerInternal.addExternalStoragePolicy( + new StorageManagerInternal.ExternalStorageMountPolicy() { @Override public int getMountMode(int uid, String packageName) { if (Process.isIsolated(uid)) { @@ -19263,7 +19264,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } /** - * Called by MountService when the initial ASECs to scan are available. + * Called by StorageManagerService when the initial ASECs to scan are available. * Should block until all the ASEC containers are finished being scanned. */ public void scanAvailableAsecs() { @@ -20775,7 +20776,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } // kill any non-foreground processes so we restart them and // grant/revoke the GID. - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); if (am != null) { final long token = Binder.clearCallingIdentity(); try { @@ -21242,6 +21243,14 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override + public boolean isPackageEphemeral(int userId, String packageName) { + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + return p != null ? p.applicationInfo.isEphemeralApp() : false; + } + } + + @Override public boolean wasPackageEverLaunched(String packageName, int userId) { synchronized (mPackages) { return mSettings.wasPackageEverLaunchedLPr(packageName, userId); @@ -21266,6 +21275,14 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public String getNameForUid(int uid) { return PackageManagerService.this.getNameForUid(uid); } + + @Override + public void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj, + Intent origIntent, String resolvedType, Intent launchIntent, + String callingPackage, int userId) { + PackageManagerService.this.requestEphemeralResolutionPhaseTwo( + responseObj, origIntent, resolvedType, launchIntent, callingPackage, userId); + } } @Override diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 42cc3a83c3d7..eef8ce22ab48 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1415,7 +1415,6 @@ final class Settings { VersionInfo ver = mVersion.get(volumeUuid); if (ver == null) { ver = new VersionInfo(); - ver.forceCurrent(); mVersion.put(volumeUuid, ver); } return ver; @@ -2802,8 +2801,8 @@ final class Settings { "No settings file; creating initial state"); // It's enough to just touch version details to create them // with default values - findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL); - findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL); + findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); + findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); return false; } str = new FileInputStream(mSettingsFilename); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 38d69ed287e1..d558b07a7a70 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -635,11 +635,7 @@ class ShortcutPackage extends ShortcutPackageItem { return false; // Shouldn't happen. } - // Always scan the settings app, since its version code is the same for DR and MR1. - // TODO Fix it properly: b/32554059 - final boolean isSettings = "com.android.settings".equals(getPackageName()); - - if (!isNewApp && !forceRescan && !isSettings) { + if (!isNewApp && !forceRescan) { // Return if the package hasn't changed, ie: // - version code hasn't change // - lastUpdateTime hasn't change @@ -656,11 +652,6 @@ class ShortcutPackage extends ShortcutPackageItem { return false; } } - if (isSettings) { - if (ShortcutService.DEBUG) { - Slog.d(TAG, "Always scan settings."); - } - } } finally { s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start); } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 37acf5cc4a0f..7b877f777c19 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.IUidObserver; import android.app.usage.UsageStatsManagerInternal; @@ -467,8 +466,8 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public void onUidGone(int uid) throws RemoteException { - handleOnUidStateChanged(uid, ActivityManager.MAX_PROCESS_STATE); + public void onUidGone(int uid, boolean disabled) throws RemoteException { + handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT); } @Override @@ -476,7 +475,7 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public void onUidIdle(int uid) throws RemoteException { + public void onUidIdle(int uid, boolean disabled) throws RemoteException { } }; @@ -497,8 +496,7 @@ public class ShortcutService extends IShortcutService.Stub { } private boolean isProcessStateForeground(int processState) { - return (processState != ActivityManager.PROCESS_STATE_NONEXISTENT) - && (processState <= PROCESS_STATE_FOREGROUND_THRESHOLD); + return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD; } boolean isUidForegroundLocked(int uid) { @@ -2667,8 +2665,7 @@ public class ShortcutService extends IShortcutService.Stub { } } - rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime(), - /* forceRescan=*/ false); + rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime()); } } finally { logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start); @@ -2676,8 +2673,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyStates(); } - private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime, - boolean forceRescan) { + private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) { final ShortcutUser user = getUserShortcutsLocked(userId); // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime @@ -2689,7 +2685,8 @@ public class ShortcutService extends IShortcutService.Stub { // Then for each installed app, publish manifest shortcuts when needed. forUpdatedPackages(userId, lastScanTime, afterOta, ai -> { user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId); - user.rescanPackageIfNeeded(ai.packageName, forceRescan); + + user.rescanPackageIfNeeded(ai.packageName, /* forceRescan= */ true); }); // Write the time just before the scan, because there may be apps that have just @@ -2937,32 +2934,26 @@ public class ShortcutService extends IShortcutService.Stub { private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta, Consumer<ApplicationInfo> callback) { if (DEBUG) { - Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime); + Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime + + " afterOta=" + afterOta); } final List<PackageInfo> list = getInstalledPackages(userId); for (int i = list.size() - 1; i >= 0; i--) { final PackageInfo pi = list.get(i); // If the package has been updated since the last scan time, then scan it. - // Also if it's a system app with no update, lastUpdateTime is not reliable, so - // just scan it. - if (pi.lastUpdateTime >= lastScanTime - || (afterOta && isPureSystemApp(pi.applicationInfo))) { + // Also if it's right after an OTA, always re-scan all apps anyway, since the + // shortcut parser might have changed. + if (afterOta || (pi.lastUpdateTime >= lastScanTime)) { if (DEBUG) { - Slog.d(TAG, "Found updated package " + pi.packageName); + Slog.d(TAG, "Found updated package " + pi.packageName + + " updateTime=" + pi.lastUpdateTime); } callback.accept(pi.applicationInfo); } } } - /** - * @return true if it's a system app with no updates. - */ - private boolean isPureSystemApp(ApplicationInfo ai) { - return ai.isSystemApp() && !ai.isUpdatedSystemApp(); - } - private boolean isApplicationFlagSet(@NonNull String packageName, int userId, int flags) { final ApplicationInfo ai = injectApplicationInfoWithUninstalled(packageName, userId); return (ai != null) && ((ai.flags & flags) == flags); @@ -3213,8 +3204,8 @@ public class ShortcutService extends IShortcutService.Stub { // Rescan all packages to re-publish manifest shortcuts and do other checks. rescanUpdatedPackagesLocked(userId, - 0, // lastScanTime = 0; rescan all packages. - /* forceRescan= */ true); + 0 // lastScanTime = 0; rescan all packages. + ); saveUserLocked(userId); } @@ -3677,7 +3668,8 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting void injectRegisterUidObserver(IUidObserver observer, int which) { try { - ActivityManagerNative.getDefault().registerUidObserver(observer, which, null); + ActivityManager.getService().registerUidObserver(observer, which, + ActivityManager.PROCESS_STATE_UNKNOWN, null); } catch (RemoteException shouldntHappen) { } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 67488ce37d81..5b47b6f1da01 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -26,7 +26,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.IActivityManager; import android.app.IStopUserCallback; @@ -757,11 +756,11 @@ public class UserManagerService extends IUserManager.Stub { long identity = Binder.clearCallingIdentity(); try { if (enableQuietMode) { - ActivityManagerNative.getDefault().stopUser(userHandle, /* force */true, null); + ActivityManager.getService().stopUser(userHandle, /* force */true, null); LocalServices.getService(ActivityManagerInternal.class) .killForegroundAppsForUser(userHandle); } else { - ActivityManagerNative.getDefault().startUserInBackground(userHandle); + ActivityManager.getService().startUserInBackground(userHandle); } } catch (RemoteException e) { Slog.e(LOG_TAG, "fail to start/stop user for quiet mode", e); @@ -1414,7 +1413,7 @@ public class UserManagerService extends IUserManager.Stub { // First, invalidate all cached values. mCachedEffectiveUserRestrictions.clear(); - // We don't want to call into ActivityManagerNative while taking a lock, so we'll call + // We don't want to call into ActivityManagerService while taking a lock, so we'll call // it on a handler. final Runnable r = new Runnable() { @Override @@ -1422,9 +1421,9 @@ public class UserManagerService extends IUserManager.Stub { // Then get the list of running users. final int[] runningUsers; try { - runningUsers = ActivityManagerNative.getDefault().getRunningUserIds(); + runningUsers = ActivityManager.getService().getRunningUserIds(); } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to access ActivityManagerNative"); + Log.w(LOG_TAG, "Unable to access ActivityManagerService"); return; } // Then re-calculate the effective restrictions and apply, only for running users. @@ -2536,7 +2535,7 @@ public class UserManagerService extends IUserManager.Stub { if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle); int res; try { - res = ActivityManagerNative.getDefault().stopUser(userHandle, /* force= */ true, + res = ActivityManager.getService().stopUser(userHandle, /* force= */ true, new IStopUserCallback.Stub() { @Override public void userStopped(int userId) { @@ -3259,7 +3258,7 @@ public class UserManagerService extends IUserManager.Stub { } private int runList(PrintWriter pw) throws RemoteException { - final IActivityManager am = ActivityManagerNative.getDefault(); + final IActivityManager am = ActivityManager.getService(); final List<UserInfo> users = getUsers(false); if (users == null) { pw.println("Error: couldn't get users"); diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 3df13a9c637f..9fe0922d3c87 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -23,7 +23,6 @@ import com.android.internal.util.Preconditions; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.content.ContentResolver; import android.content.Context; import android.os.Binder; @@ -411,7 +410,7 @@ public class UserRestrictionsUtils { int currentUser = ActivityManager.getCurrentUser(); if (currentUser != userId && userId != UserHandle.USER_SYSTEM) { try { - ActivityManagerNative.getDefault().stopUser(userId, false, null); + ActivityManager.getService().stopUser(userId, false, null); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java index a8bd4d289616..d4adcc4b8383 100644 --- a/services/core/java/com/android/server/policy/GlobalActions.java +++ b/services/core/java/com/android/server/policy/GlobalActions.java @@ -19,7 +19,7 @@ package com.android.server.policy; import com.android.internal.app.AlertController; import com.android.internal.app.AlertController.AlertParams; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.EmergencyAffordanceManager; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; @@ -27,7 +27,6 @@ import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -434,7 +433,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac // Take an "interactive" bugreport. MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE); - ActivityManagerNative.getDefault().requestBugReport( + ActivityManager.getService().requestBugReport( ActivityManager.BUGREPORT_OPTION_INTERACTIVE); } catch (RemoteException e) { } @@ -452,7 +451,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac try { // Take a "full" bugreport. MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL); - ActivityManagerNative.getDefault().requestBugReport( + ActivityManager.getService().requestBugReport( ActivityManager.BUGREPORT_OPTION_FULL); } catch (RemoteException e) { } @@ -592,7 +591,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private UserInfo getCurrentUser() { try { - return ActivityManagerNative.getDefault().getCurrentUser(); + return ActivityManager.getService().getCurrentUser(); } catch (RemoteException re) { return null; } @@ -620,7 +619,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac + (isCurrentUser ? " \u2714" : "")) { public void onPress() { try { - ActivityManagerNative.getDefault().switchUser(user.id); + ActivityManager.getService().switchUser(user.id); } catch (RemoteException re) { Log.e(TAG, "Couldn't switch user " + re); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b7067d2da261..ccdda1328a8d 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -114,7 +114,6 @@ import android.app.ActivityManager; import android.app.ActivityManager.StackId; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal.SleepToken; -import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.IUiModeManager; import android.app.ProgressDialog; @@ -226,6 +225,7 @@ import com.android.server.GestureLauncherService; import com.android.server.LocalServices; import com.android.server.policy.keyguard.KeyguardServiceDelegate; import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener; +import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.AppTransition; @@ -2677,9 +2677,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, - int uiMode) { - if (mHasNavigationBar) { + public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { + // TODO(multi-display): Support navigation bar on secondary displays. + if (displayId == Display.DEFAULT_DISPLAY && mHasNavigationBar) { // For a basic navigation bar, when we are in landscape mode we place // the navigation bar to the side. if (mNavigationBarCanMove && fullWidth > fullHeight) { @@ -2698,9 +2699,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, - int uiMode) { - if (mHasNavigationBar) { + public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { + // TODO(multi-display): Support navigation bar on secondary displays. + if (displayId == Display.DEFAULT_DISPLAY && mHasNavigationBar) { // For a basic navigation bar, when we are in portrait mode we place // the navigation bar to the bottom. if (!mNavigationBarCanMove || fullWidth < fullHeight) { @@ -2711,18 +2713,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) { - return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode); + public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { + return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayId); } @Override - public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) { + public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { // There is a separate status bar at the top of the display. We don't count that as part // of the fixed decor, since it can hide; however, for purposes of configurations, // we do want to exclude it since applications can't generally use that part // of the screen. - return getNonDecorDisplayHeight( - fullWidth, fullHeight, rotation, uiMode) - mStatusBarHeight; + // TODO(multi-display): Support status bars on secondary displays. + if (displayId == Display.DEFAULT_DISPLAY) { + return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayId) + - mStatusBarHeight; + } + return fullHeight; } @Override @@ -3942,7 +3950,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void onKeyguardExitResult(boolean success) { if (success) { try { - ActivityManagerNative.getDefault().stopAppSwitches(); + ActivityManager.getService().stopAppSwitches(); } catch (RemoteException e) { } sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); @@ -3956,7 +3964,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // no keyguard stuff to worry about, just launch home! try { - ActivityManagerNative.getDefault().stopAppSwitches(); + ActivityManager.getService().stopAppSwitches(); } catch (RemoteException e) { } if (mRecentsVisible) { @@ -6956,7 +6964,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public void systemReady() { - mKeyguardDelegate = new KeyguardServiceDelegate(mContext); + mKeyguardDelegate = new KeyguardServiceDelegate(mContext, + new StateCallback() { + @Override + public void onTrustedChanged() { + mWindowManagerFuncs.notifyKeyguardTrustedChanged(); + } + }); mKeyguardDelegate.onSystemReady(); readCameraLensCoverState(); @@ -7333,7 +7347,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (false) { // This code always brings home to the front. try { - ActivityManagerNative.getDefault().stopAppSwitches(); + ActivityManager.getService().stopAppSwitches(); } catch (RemoteException e) { } sendCloseSystemWindows(); @@ -7346,11 +7360,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry. Log.d(TAG, "UTS-TEST-MODE"); } else { - ActivityManagerNative.getDefault().stopAppSwitches(); + ActivityManager.getService().stopAppSwitches(); sendCloseSystemWindows(); Intent dock = createHomeDockIntent(); if (dock != null) { - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivityAsUser(null, null, dock, dock.resolveTypeIfNeeded(mContext.getContentResolver()), null, null, 0, @@ -7361,7 +7375,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - int result = ActivityManagerNative.getDefault() + int result = ActivityManager.getService() .startActivityAsUser(null, null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), null, null, 0, diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 28f36f779e89..f37f98786fed 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -1,8 +1,6 @@ package com.android.server.policy.keyguard; import android.app.ActivityManager; -import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -15,13 +13,11 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.util.Slog; -import android.view.View; import android.view.WindowManagerPolicy.OnKeyguardExitResult; import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardService; -import com.android.server.LocalServices; import com.android.server.UiThread; import java.io.PrintWriter; @@ -47,6 +43,8 @@ public class KeyguardServiceDelegate { private final Context mContext; private final Handler mHandler; private final KeyguardState mKeyguardState = new KeyguardState(); + private final KeyguardStateMonitor.StateCallback mCallback; + private DrawnListener mDrawnListenerWhenConnect; private static final class KeyguardState { @@ -119,9 +117,10 @@ public class KeyguardServiceDelegate { } }; - public KeyguardServiceDelegate(Context context) { + public KeyguardServiceDelegate(Context context, KeyguardStateMonitor.StateCallback callback) { mContext = context; mHandler = UiThread.getHandler(); + mCallback = callback; } public void bindService(Context context) { @@ -155,7 +154,7 @@ public class KeyguardServiceDelegate { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)"); mKeyguardService = new KeyguardServiceWrapper(mContext, - IKeyguardService.Stub.asInterface(service)); + IKeyguardService.Stub.asInterface(service), mCallback); if (mKeyguardState.systemIsReady) { // If the system is ready, it means keyguard crashed and restarted. mKeyguardService.onSystemReady(); @@ -195,7 +194,7 @@ public class KeyguardServiceDelegate { mKeyguardState.reset(); mHandler.post(() -> { try { - ActivityManagerNative.getDefault().setLockScreenShown(true); + ActivityManager.getService().setLockScreenShown(true); } catch (RemoteException e) { // Local call. } diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java index b457f8d8ed82..c4a0dd364d76 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java @@ -39,9 +39,10 @@ public class KeyguardServiceWrapper implements IKeyguardService { private IKeyguardService mService; private String TAG = "KeyguardServiceWrapper"; - public KeyguardServiceWrapper(Context context, IKeyguardService service) { + public KeyguardServiceWrapper(Context context, IKeyguardService service, + KeyguardStateMonitor.StateCallback callback) { mService = service; - mKeyguardStateMonitor = new KeyguardStateMonitor(context, service); + mKeyguardStateMonitor = new KeyguardStateMonitor(context, service, callback); } @Override // Binder interface diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index f19f0aa4f978..941cd4441e23 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -49,10 +49,12 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { private int mCurrentUserId; private final LockPatternUtils mLockPatternUtils; + private final StateCallback mCallback; - public KeyguardStateMonitor(Context context, IKeyguardService service) { + public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) { mLockPatternUtils = new LockPatternUtils(context); mCurrentUserId = ActivityManager.getCurrentUser(); + mCallback = callback; try { service.addStateMonitorCallback(this); @@ -107,6 +109,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { @Override // Binder interface public void onTrustedChanged(boolean trusted) { mTrusted = trusted; + mCallback.onTrustedChanged(); } @Override // Binder interface @@ -114,6 +117,10 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { mHasLockscreenWallpaper = hasLockscreenWallpaper; } + public interface StateCallback { + void onTrustedChanged(); + } + public void dump(String prefix, PrintWriter pw) { pw.println(prefix + TAG); prefix += " "; diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 00700b86d4e8..b215998de222 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -25,7 +25,6 @@ import com.android.internal.app.IBatteryStats; import com.android.server.EventLogTags; import com.android.server.LocalServices; -import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index d755e58c2ba2..1790554a258b 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2731,6 +2731,8 @@ public final class PowerManagerService extends SystemService } } else { disabled = !wakeLock.mUidState.mActive && + wakeLock.mUidState.mProcState + != ActivityManager.PROCESS_STATE_NONEXISTENT && wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER; } } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index a920d5457a2d..cd966ef323b7 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -43,8 +43,8 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.Vibrator; import android.os.SystemVibrator; -import android.os.storage.IMountService; -import android.os.storage.IMountShutdownObserver; +import android.os.storage.IStorageShutdownObserver; +import android.os.storage.IStorageManager; import android.system.ErrnoException; import android.system.Os; @@ -442,30 +442,30 @@ public final class ShutdownThread extends Thread { sInstance.setRebootProgress(RADIO_STOP_PERCENT, null); } - // Shutdown MountService to ensure media is in a safe state - IMountShutdownObserver observer = new IMountShutdownObserver.Stub() { + // Shutdown StorageManagerService to ensure media is in a safe state + IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() { public void onShutDownComplete(int statusCode) throws RemoteException { - Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown"); + Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown"); actionDone(); } }; - Log.i(TAG, "Shutting down MountService"); + Log.i(TAG, "Shutting down StorageManagerService"); // Set initial variables and time out time. mActionDone = false; final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME; synchronized (mActionDoneSync) { try { - final IMountService mount = IMountService.Stub.asInterface( + final IStorageManager storageManager = IStorageManager.Stub.asInterface( ServiceManager.checkService("mount")); - if (mount != null) { - mount.shutdown(observer); + if (storageManager != null) { + storageManager.shutdown(observer); } else { - Log.w(TAG, "MountService unavailable for shutdown"); + Log.w(TAG, "StorageManagerService unavailable for shutdown"); } } catch (Exception e) { - Log.e(TAG, "Exception during MountService shutdown", e); + Log.e(TAG, "Exception during StorageManagerService shutdown", e); } while (!mActionDone) { long delay = endShutTime - SystemClock.elapsedRealtime(); diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index f3b9b18e6c5e..b5aa4a949241 100644 --- a/services/core/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java @@ -17,7 +17,6 @@ package com.android.server.search; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.IActivityManager; import android.app.ISearchManager; @@ -306,7 +305,7 @@ public class SearchManagerService extends ISearchManager.Stub { try { Intent intent = new Intent(Intent.ACTION_ASSIST); intent.setComponent(comp); - IActivityManager am = ActivityManagerNative.getDefault(); + IActivityManager am = ActivityManager.getService(); return am.launchAssistIntent(intent, ActivityManager.ASSIST_CONTEXT_BASIC, hint, userHandle, args); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java new file mode 100644 index 000000000000..23be9a3a27f7 --- /dev/null +++ b/services/core/java/com/android/server/storage/AppFuseBridge.java @@ -0,0 +1,95 @@ +/* + * 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.storage; + +import android.annotation.CallSuper; +import android.annotation.WorkerThread; +import android.os.Handler; +import android.os.ParcelFileDescriptor; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; +import com.android.internal.os.AppFuseMount; +import libcore.io.IoUtils; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +public class AppFuseBridge implements Runnable { + private static final String TAG = AppFuseBridge.class.getSimpleName(); + + private final FileDescriptor mDeviceFd; + private final FileDescriptor mProxyFd; + private final CountDownLatch mMountLatch = new CountDownLatch(1); + + /** + * @param deviceFd FD of /dev/fuse. Ownership of fd is taken by AppFuseBridge. + * @param proxyFd FD of socket pair. Ownership of fd is taken by AppFuseBridge. + */ + private AppFuseBridge(FileDescriptor deviceFd, FileDescriptor proxyFd) { + mDeviceFd = deviceFd; + mProxyFd = proxyFd; + } + + public static AppFuseMount startMessageLoop( + int uid, + String name, + FileDescriptor deviceFd, + Handler handler, + ParcelFileDescriptor.OnCloseListener listener) + throws IOException, ErrnoException, InterruptedException { + final FileDescriptor localFd = new FileDescriptor(); + final FileDescriptor remoteFd = new FileDescriptor(); + // Needs to specify OsConstants.SOCK_SEQPACKET to keep message boundaries. + Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, remoteFd, localFd); + + // Caller must invoke #start() after instantiate AppFuseBridge. + // Otherwise FDs will be leaked. + final AppFuseBridge bridge = new AppFuseBridge(deviceFd, localFd); + final Thread thread = new Thread(bridge, TAG); + thread.start(); + try { + bridge.mMountLatch.await(); + } catch (InterruptedException error) { + throw error; + } + return new AppFuseMount( + new File("/mnt/appfuse/" + uid + "_" + name), + ParcelFileDescriptor.fromFd(remoteFd, handler, listener)); + } + + @Override + public void run() { + // deviceFd and proxyFd must be closed in native_start_loop. + final int deviceFd = mDeviceFd.getInt$(); + final int proxyFd = mProxyFd.getInt$(); + mDeviceFd.setInt$(-1); + mProxyFd.setInt$(-1); + native_start_loop(deviceFd, proxyFd); + } + + // Used by com_android_server_storage_AppFuse.cpp. + private void onMount() { + mMountLatch.countDown(); + } + + private native boolean native_start_loop(int deviceFd, int proxyFd); +} diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 62f54685a090..9d02940e21a5 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -26,7 +26,6 @@ import org.xmlpull.v1.XmlPullParserException; import android.Manifest; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustListener; import android.app.trust.ITrustManager; @@ -868,7 +867,7 @@ public class TrustManagerService extends SystemService { } if (locked) { try { - ActivityManagerNative.getDefault().notifyLockedProfile(userId); + ActivityManager.getService().notifyLockedProfile(userId); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 96662b5b28c3..3645c24043ca 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -26,7 +26,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.IWallpaperManager; @@ -959,7 +958,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { }, shutdownFilter); try { - ActivityManagerNative.getDefault().registerUserSwitchObserver( + ActivityManager.getService().registerUserSwitchObserver( new UserSwitchObserver() { @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) { diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java index 302f9f6c98ba..61319cf1e30e 100644 --- a/services/core/java/com/android/server/webkit/SystemImpl.java +++ b/services/core/java/com/android/server/webkit/SystemImpl.java @@ -16,7 +16,7 @@ package com.android.server.webkit; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.AppGlobals; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -200,7 +200,7 @@ public class SystemImpl implements SystemInterface { @Override public void killPackageDependents(String packageName) { try { - ActivityManagerNative.getDefault().killPackageDependents(packageName, + ActivityManager.getService().killPackageDependents(packageName, UserHandle.USER_ALL); } catch (RemoteException e) { } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 6d97796d3d3e..0a7454f31669 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -36,6 +36,7 @@ import android.webkit.WebViewProviderResponse; import com.android.server.SystemService; import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Arrays; /** @@ -259,5 +260,18 @@ public class WebViewUpdateService extends SystemService { Binder.restoreCallingIdentity(callingId); } } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump webviewupdate service from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + return; + } + + WebViewUpdateService.this.mImpl.dumpState(pw); + } } } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java index 453e7458b19c..1a77c68d83d2 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java @@ -30,6 +30,7 @@ import android.webkit.WebViewFactory; import android.webkit.WebViewProviderInfo; import android.webkit.WebViewProviderResponse; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -673,6 +674,27 @@ public class WebViewUpdateServiceImpl { mMinimumVersionCode = minimumVersionCode; return mMinimumVersionCode; } + + public void dumpState(PrintWriter pw) { + synchronized (mLock) { + if (mCurrentWebViewPackage == null) { + pw.println(" Current WebView package is null"); + } else { + pw.println(String.format(" Current WebView package (name, version): (%s, %s)", + mCurrentWebViewPackage.packageName, + mCurrentWebViewPackage.versionName)); + } + pw.println(String.format(" Minimum WebView version code: %d", + mMinimumVersionCode)); + pw.println(String.format(" Number of relros started: %d", + mNumRelroCreationsStarted)); + pw.println(String.format(" Number of relros finished: %d", + mNumRelroCreationsFinished)); + pw.println(String.format(" WebView package dirty: %b", mWebViewPackageDirty)); + pw.println(String.format(" Any WebView package installed: %b", + mAnyWebViewInstalled)); + } + } } private static boolean providerHasValidSignature(WebViewProviderInfo provider, @@ -741,4 +763,14 @@ public class WebViewUpdateServiceImpl { mSystemInterface.setMultiProcessEnabledFromContext(mContext); } } + + /** + * Dump the state of this Service. + */ + void dumpState(PrintWriter pw) { + pw.println("Current WebView Update Service state"); + pw.println(String.format(" Fallback logic enabled: %b", + mSystemInterface.isFallbackLogicEnabled())); + mWebViewUpdater.dumpState(pw); + } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 670b9ccdf5f6..49ffa22b53e3 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -649,15 +649,12 @@ final class AccessibilityController { private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) { final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked(); - final ReadOnlyWindowList windowList = dc.getReadOnlyWindowList(); - final int windowCount = windowList.size(); - for (int i = 0; i < windowCount; i++) { - final WindowState windowState = windowList.get(i); - if (windowState.isOnScreen() && windowState.isVisibleLw() && - !windowState.mWinAnimator.mEnterAnimationPending) { - outWindows.put(windowState.mLayer, windowState); + dc.forAllWindows((w) -> { + if (w.isOnScreen() && w.isVisibleLw() + && !w.mWinAnimator.mEnterAnimationPending) { + outWindows.put(w.mLayer, w); } - } + }, false /* traverseTopToBottom */ ); } private final class ViewportWindow { @@ -1034,7 +1031,6 @@ final class AccessibilityController { boolean focusedWindowAdded = false; final int visibleWindowCount = visibleWindows.size(); - int skipRemainingWindowsForTaskId = -1; HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>(); for (int i = visibleWindowCount - 1; i >= 0; i--) { final WindowState windowState = visibleWindows.valueAt(i); @@ -1297,14 +1293,11 @@ final class AccessibilityController { private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) { final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked(); - final ReadOnlyWindowList windowList = dc.getReadOnlyWindowList(); - final int windowCount = windowList.size(); - for (int i = 0; i < windowCount; i++) { - final WindowState windowState = windowList.get(i); - if (windowState.isVisibleLw()) { - outWindows.put(windowState.mLayer, windowState); + dc.forAllWindows((w) -> { + if (w.isVisibleLw()) { + outWindows.put(w.mLayer, w); } - } + }, false /* traverseTopToBottom */ ); } private class MyHandler extends Handler { diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java index e1b598a03204..c42647ed0aee 100644 --- a/services/core/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java @@ -411,7 +411,7 @@ public class AppWindowAnimator { } if (mService.mInputMethodTarget != null && mService.mInputMethodTarget.mAppToken == mAppToken) { - mAppToken.getDisplayContent().moveInputMethodWindowsIfNeeded(true); + mAppToken.getDisplayContent().computeImeTarget(true /* updateImeTarget */); } if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 622eece52ca1..45695960853f 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -47,6 +47,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE import static com.android.server.wm.WindowManagerService.logWithStack; import android.os.Debug; +import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; @@ -66,6 +67,7 @@ import android.view.animation.Animation; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.function.Function; class AppTokenList extends ArrayList<AppWindowToken> { } @@ -411,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; @@ -1003,10 +1006,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree tStartingWindow.mToken = this; tStartingWindow.mAppToken = this; - if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, - "Removing starting window: " + tStartingWindow); - getDisplayContent().removeFromWindowList(tStartingWindow); - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, + if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing starting " + tStartingWindow + " from " + fromToken); fromToken.removeChild(tStartingWindow); fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow); @@ -1256,16 +1256,21 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } - int rebuildWindowListUnchecked(int addIndex) { - return super.rebuildWindowList(addIndex); - } - @Override - int rebuildWindowList(int addIndex) { + boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { + // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent + // before the non-exiting app tokens. So, we skip the exiting app tokens here. + // TODO: Investigate if we need to continue to do this or if we can just process them + // in-order. if (mIsExiting && !waitingForReplacement()) { - return addIndex; + return false; } - return rebuildWindowListUnchecked(addIndex); + return forAllWindowsUnchecked(callback, traverseTopToBottom); + } + + boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { + return super.forAllWindows(callback, traverseTopToBottom); } @Override @@ -1312,6 +1317,32 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mLastContainsShowWhenLockedWindow = containsShowWhenLocked; } + WindowState getImeTargetBelowWindow(WindowState w) { + final int index = mChildren.indexOf(w); + if (index > 0) { + final WindowState target = mChildren.get(index - 1); + if (target.canBeImeTarget()) { + return target; + } + } + return null; + } + + WindowState getHighestAnimLayerWindow(WindowState currentTarget) { + WindowState candidate = null; + for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) { + final WindowState w = mChildren.get(i); + if (w.mRemoved) { + continue; + } + if (candidate == null || w.mWinAnimator.mAnimLayer > + candidate.mWinAnimator.mAnimLayer) { + candidate = w; + } + } + return candidate; + } + @Override void dump(PrintWriter pw, String prefix) { super.dump(pw, prefix); diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index 5bfece414446..cf5cecdaf797 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -96,8 +96,8 @@ public class BoundsAnimationController { private final class BoundsAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { private final AnimateBoundsUser mTarget; - private final Rect mFrom; - private final Rect mTo; + private final Rect mFrom = new Rect(); + private final Rect mTo = new Rect(); private final Rect mTmpRect = new Rect(); private final Rect mTmpTaskBounds = new Rect(); private final boolean mMoveToFullScreen; @@ -117,8 +117,8 @@ public class BoundsAnimationController { boolean moveToFullScreen, boolean replacement) { super(); mTarget = target; - mFrom = from; - mTo = to; + mFrom.set(from); + mTo.set(to); mMoveToFullScreen = moveToFullScreen; mReplacement = replacement; addUpdateListener(this); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ec4cdf2b0f3d..24b9d6944ecc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -33,10 +33,6 @@ import static android.view.View.GONE; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_TOP; -import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; -import static android.view.WindowManager.INPUT_CONSUMER_PIP; -import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER; -import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; @@ -44,13 +40,10 @@ import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -64,7 +57,6 @@ import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; @@ -77,10 +69,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -94,7 +84,6 @@ import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT; import static com.android.server.wm.WindowManagerService.dipToPixel; -import static com.android.server.wm.WindowManagerService.localLOGV; import static com.android.server.wm.WindowManagerService.logSurface; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; @@ -120,21 +109,16 @@ import android.util.DisplayMetrics; import android.util.Slog; import android.view.Display; import android.view.DisplayInfo; -import android.view.IWindow; -import android.view.InputChannel; import android.view.Surface; import android.view.SurfaceControl; import android.view.WindowManagerPolicy; -import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.ToBooleanFunction; import com.android.internal.view.IInputMethodClient; -import com.android.server.input.InputWindowHandle; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.io.StringWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; @@ -171,8 +155,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private final NonAppWindowContainers mImeWindowsContainers = new NonAppWindowContainers("mImeWindowsContainers"); - // Z-ordered (bottom-most first) list of all Window objects. - private final WindowList mWindows = new WindowList(); + private WindowState mTmpWindow; // Mapping from a token IBinder to a WindowToken object on this display. private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap(); @@ -229,21 +212,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>(); - /** Used when rebuilding window list to keep track of windows that have been removed. */ - private WindowState[] mRebuildTmp = new WindowState[20]; - - /** - * Temporary list for comparison. Always clear this after use so we don't end up with - * orphaned windows references - */ - private final ArrayList<WindowState> mTmpWindows = new ArrayList<>(); + private boolean mHaveBootMsg = false; + private boolean mHaveApp = false; + private boolean mHaveWallpaper = false; + private boolean mHaveKeyguard = true; private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList(); private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult = new TaskForResizePointSearchResult(); - private final GetWindowOnDisplaySearchResult mTmpGetWindowOnDisplaySearchResult = - new GetWindowOnDisplaySearchResult(); + private final ApplySurfaceChangesTransactionState mTmpApplySurfaceChangesTransactionState = + new ApplySurfaceChangesTransactionState(); + private final ScreenshotApplicationState mScreenshotApplicationState = + new ScreenshotApplicationState(); // True if this display is in the process of being removed. Used to determine if the removal of // the display's direct children should be allowed. @@ -452,17 +433,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo @Override void onAppTransitionDone() { super.onAppTransitionDone(); - rebuildAppWindowList(); + mService.mWindowsChanged = true; } @Override int getOrientation() { final WindowManagerPolicy policy = mService.mPolicy; - // TODO: All the logic before the last return statement in this method should really go in - // #NonAppWindowContainer.getOrientation() since it is trying to decide orientation based - // on non-app windows. But, we can not do that until the window list is always correct in - // terms of z-ordering based on layers. if (mService.mDisplayFrozen) { if (mService.mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { if (DEBUG_ORIENTATION) Slog.v(TAG_WM, @@ -483,31 +460,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mService.mLastOrientation; } } else { - for (int pos = mWindows.size() - 1; pos >= 0; --pos) { - final WindowState win = mWindows.get(pos); - if (win.mAppToken != null) { - // We hit an application window. so the orientation will be determined by the - // app window. No point in continuing further. - break; - } - if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) { - continue; - } - int req = win.mAttrs.screenOrientation; - if(req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND) { - continue; - } - - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req); - if (policy.isKeyguardHostWindow(win.mAttrs)) { - mService.mLastKeyguardForcedOrientation = req; - } - return (mService.mLastWindowForcedOrientation = req); - } - mService.mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED; - - if (policy.isKeyguardShowingAndNotOccluded()) { - return mService.mLastKeyguardForcedOrientation; + final int orientation = mAboveAppWindowsContainers.getOrientation(); + if (orientation != SCREEN_ORIENTATION_UNSET) { + return orientation; } } @@ -724,7 +679,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo win.getTouchableRegion(mTmpRegion); mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION); } - if (getDockedStackLocked() != null) { + // TODO(multi-display): Support docked stacks on secondary displays. + if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) { mDividerControllerLocked.getTouchRegion(mTmpRect); mTmpRegion.set(mTmpRect); mTouchExcludeRegion.op(mTmpRegion, Op.UNION); @@ -734,22 +690,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + @Override void switchUser() { - final int count = mWindows.size(); - for (int i = 0; i < count; i++) { - final WindowState win = mWindows.get(i); - if (win.isHiddenFromUserLocked()) { - if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + win - + ", attrs=" + win.mAttrs.type + ", belonging to " + win.mOwnerUid); - win.hideLw(false); - } - } - - for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { - mTaskStackContainers.get(stackNdx).switchUser(); - } - - rebuildAppWindowList(); + super.switchUser(); + mService.mWindowsChanged = true; } private void resetAnimationBackgroundAnimator() { @@ -911,19 +855,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void setInputMethodAnimLayerAdjustment(int adj) { if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj); mInputMethodAnimLayerAdjustment = adj; - final WindowState imw = mService.mInputMethodWindow; - if (imw != null) { - imw.adjustAnimLayer(adj); - } - for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) { - final WindowState dialog = mService.mInputMethodDialogs.get(i); - // TODO: This and other places setting mAnimLayer can probably use WS.adjustAnimLayer, - // but need to make sure we are not setting things twice for child windows that are - // already in the list. - dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj; - if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw - + " anim layer: " + dialog.mWinAnimator.mAnimLayer); - } + mImeWindowsContainers.forAllWindows(w -> { + w.adjustAnimLayer(adj); + }, true /* traverseTopToBottom */); } /** @@ -932,11 +866,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * suddenly disappear. */ int getLayerForAnimationBackground(WindowStateAnimator winAnimator) { - for (int i = mWindows.size() - 1; i >= 0; --i) { - final WindowState win = mWindows.get(i); - if (win.mIsWallpaper && win.isVisibleNow()) { - return win.mWinAnimator.mAnimLayer; - } + final WindowState visibleWallpaper = mBelowAppWindowsContainers.getWindow( + w -> w.mIsWallpaper && w.isVisibleNow()); + + if (visibleWallpaper != null) { + return visibleWallpaper.mWinAnimator.mAnimLayer; } return winAnimator.mAnimLayer; } @@ -1084,49 +1018,37 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** Find the visible, touch-deliverable window under the given point */ WindowState getTouchableWinAtPointLocked(float xf, float yf) { - WindowState touchedWin = null; final int x = (int) xf; final int y = (int) yf; - - for (int i = mWindows.size() - 1; i >= 0; i--) { - WindowState window = mWindows.get(i); - final int flags = window.mAttrs.flags; - if (!window.isVisibleLw()) { - continue; + final WindowState touchedWin = getWindow(w -> { + final int flags = w.mAttrs.flags; + if (!w.isVisibleLw()) { + return false; } if ((flags & FLAG_NOT_TOUCHABLE) != 0) { - continue; + return false; } - window.getVisibleBounds(mTmpRect); + w.getVisibleBounds(mTmpRect); if (!mTmpRect.contains(x, y)) { - continue; + return false; } - window.getTouchableRegion(mTmpRegion); + w.getTouchableRegion(mTmpRegion); final int touchFlags = flags & (FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL); - if (mTmpRegion.contains(x, y) || touchFlags == 0) { - touchedWin = window; - break; - } - } + return mTmpRegion.contains(x, y) || touchFlags == 0; + }); return touchedWin; } boolean canAddToastWindowForUid(int uid) { // We allow one toast window per UID being shown at a time. - final int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - final WindowState window = mWindows.get(i); - if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid - && !window.mPermanentlyHidden && !window.mAnimatingExit - && !window.mRemoveOnExit) { - return false; - } - } - return true; + final WindowState win = getWindow(w -> + w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == uid && !w.mPermanentlyHidden + && !w.mWindowRemovalAllowed); + return win == null; } void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus, WindowState newFocus) { @@ -1134,410 +1056,89 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return; } final int lostFocusUid = oldFocus.mOwnerUid; - final int windowCount = mWindows.size(); final Handler handler = mService.mH; - for (int i = 0; i < windowCount; i++) { - final WindowState window = mWindows.get(i); - if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) { - if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, window)) { - handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, window), - window.mAttrs.hideTimeoutMilliseconds); + + forAllWindows(w -> { + if (w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == lostFocusUid) { + if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, w)) { + handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, w), + w.mAttrs.hideTimeoutMilliseconds); } } - } + }, false /* traverseTopToBottom */); } WindowState findFocusedWindow() { final AppWindowToken focusedApp = mService.mFocusedApp; + mTmpWindow = null; - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState win = mWindows.get(i); - - if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + i + " = " + win - + ", flags=" + win.mAttrs.flags + ", canReceive=" + win.canReceiveKeys()); + forAllWindows(w -> { + if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w + + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys()); - if (!win.canReceiveKeys()) { - continue; + if (!w.canReceiveKeys()) { + return false; } - final AppWindowToken wtoken = win.mAppToken; + final AppWindowToken wtoken = w.mAppToken; // If this window's application has been removed, just skip it. if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) { if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because " + (wtoken.removed ? "removed" : "sendingToBottom")); - continue; + return false; } if (focusedApp == null) { if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null" - + " using new focus @ " + i + " = " + win); - return win; + + " using new focus @ " + w); + mTmpWindow = w; + return true; } if (!focusedApp.windowsAreFocusable()) { // Current focused app windows aren't focusable... if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not" - + " focusable using new focus @ " + i + " = " + win); - return win; + + " focusable using new focus @ " + w); + mTmpWindow = w; + return true; } // Descend through all of the app tokens and find the first that either matches // win.mAppToken (return win) or mFocusedApp (return null). - if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING) { + if (wtoken != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) { if (focusedApp.compareTo(wtoken) > 0) { // App stack below focused app stack. No focus for you!!! if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Reached focused app=" + focusedApp); - return null; + mTmpWindow = null; + return true; } } - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " - + i + " = " + win); - return win; - } - - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows."); - return null; - } - - void addAppWindowToWindowList(final WindowState win) { - final IWindow client = win.mClient; - - WindowList tokenWindowList = getTokenWindowsOnDisplay(win.mToken); - if (!tokenWindowList.isEmpty()) { - addAppWindowExisting(win, tokenWindowList); - return; - } - - // No windows from this token on this display - if (localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window " - + client.asBinder() + " (token=" + this + ")"); - - final WindowToken wToken = win.mToken; - - // Figure out where the window should go, based on the order of applications. - mTmpGetWindowOnDisplaySearchResult.reset(); - for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.get(i); - stack.getWindowOnDisplayBeforeToken(this, wToken, mTmpGetWindowOnDisplaySearchResult); - if (mTmpGetWindowOnDisplaySearchResult.reachedToken) { - // We have reach the token we are interested in. End search. - break; - } - } - - WindowState pos = mTmpGetWindowOnDisplaySearchResult.foundWindow; - - // We now know the index into the apps. If we found an app window above, that gives us the - // position; else we need to look some more. - if (pos != null) { - // Move behind any windows attached to this one. - final WindowToken atoken = getWindowToken(pos.mClient.asBinder()); - if (atoken != null) { - tokenWindowList = getTokenWindowsOnDisplay(atoken); - final int NC = tokenWindowList.size(); - if (NC > 0) { - WindowState bottom = tokenWindowList.get(0); - if (bottom.mSubLayer < 0) { - pos = bottom; - } - } - } - addWindowToListBefore(win, pos); - return; - } - - // Continue looking down until we find the first token that has windows on this display. - mTmpGetWindowOnDisplaySearchResult.reset(); - for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.get(i); - stack.getWindowOnDisplayAfterToken(this, wToken, mTmpGetWindowOnDisplaySearchResult); - if (mTmpGetWindowOnDisplaySearchResult.foundWindow != null) { - // We have found a window after the token. End search. - break; - } - } - - pos = mTmpGetWindowOnDisplaySearchResult.foundWindow; - - if (pos != null) { - // Move in front of any windows attached to this one. - final WindowToken atoken = getWindowToken(pos.mClient.asBinder()); - if (atoken != null) { - final WindowState top = atoken.getTopWindow(); - if (top != null && top.mSubLayer >= 0) { - pos = top; - } - } - addWindowToListAfter(win, pos); - return; - } - - // Just search for the start of this layer. - final int myLayer = win.mBaseLayer; - int i; - for (i = mWindows.size() - 1; i >= 0; --i) { - final WindowState w = mWindows.get(i); - // Dock divider shares the base layer with application windows, but we want to always - // keep it above the application windows. The sharing of the base layer is intended - // for window animations, which need to be above the dock divider for the duration - // of the animation. - if (w.mBaseLayer <= myLayer && w.mAttrs.type != TYPE_DOCK_DIVIDER) { - break; - } - } - if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Based on layer: Adding window " + win + " at " + (i + 1) + " of " - + mWindows.size()); - mWindows.add(i + 1, win); - mService.mWindowsChanged = true; - } - - /** Adds this non-app window to the window list. */ - void addNonAppWindowToWindowList(WindowState win) { - // Figure out where window should go, based on layer. - int i; - for (i = mWindows.size() - 1; i >= 0; i--) { - final WindowState otherWin = mWindows.get(i); - if (otherWin.getBaseType() != TYPE_WALLPAPER && otherWin.mBaseLayer <= win.mBaseLayer) { - // Wallpaper wanders through the window list, for example to position itself - // directly behind keyguard. Because of this it will break the ordering based on - // WindowState.mBaseLayer. There might windows with higher mBaseLayer behind it and - // we don't want the new window to appear above them. An example of this is adding - // of the docked stack divider. Consider a scenario with the following ordering (top - // to bottom): keyguard, wallpaper, assist preview, apps. We want the dock divider - // to land below the assist preview, so the dock divider must ignore the wallpaper, - // with which it shares the base layer. - break; - } - } - - i++; - if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Free window: Adding window " + this + " at " + i + " of " + mWindows.size()); - mWindows.add(i, win); - mService.mWindowsChanged = true; - } - - void addToWindowList(WindowState win, int index) { - mService.mWindowsChanged = true; - mWindows.add(index, win); - } - - boolean removeFromWindowList(WindowState win) { - mService.mWindowsChanged = true; - return mWindows.remove(win); - } - - private int removeWindowAndChildrenFromWindowList(WindowState win, int interestingPos) { - int wpos = mWindows.indexOf(win); - if (wpos < 0) { - return interestingPos; - } - - if (wpos < interestingPos) interestingPos--; - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Temp removing at " + wpos + ": " + this); - mWindows.remove(wpos); - mService.mWindowsChanged = true; - int childWinCount = win.mChildren.size(); - while (childWinCount > 0) { - childWinCount--; - final WindowState cw = win.mChildren.get(childWinCount); - int cpos = mWindows.indexOf(cw); - if (cpos >= 0) { - if (cpos < interestingPos) interestingPos--; - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, - "Temp removing child at " + cpos + ": " + cw); - mWindows.remove(cpos); - } - } - return interestingPos; - } - - void addChildWindowToWindowList(WindowState win) { - final WindowState parentWindow = win.getParentWindow(); - - WindowList windowsOnSameDisplay = getTokenWindowsOnDisplay(win.mToken); + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + w); + mTmpWindow = w; + return true; + }, true /* traverseTopToBottom */); - // Figure out this window's ordering relative to the parent window. - final int wCount = windowsOnSameDisplay.size(); - final int sublayer = win.mSubLayer; - int largestSublayer = Integer.MIN_VALUE; - WindowState windowWithLargestSublayer = null; - int i; - for (i = 0; i < wCount; i++) { - WindowState w = windowsOnSameDisplay.get(i); - final int wSublayer = w.mSubLayer; - if (wSublayer >= largestSublayer) { - largestSublayer = wSublayer; - windowWithLargestSublayer = w; - } - if (sublayer < 0) { - // For negative sublayers, we go below all windows in the same sublayer. - if (wSublayer >= sublayer) { - addWindowToListBefore(win, wSublayer >= 0 ? parentWindow : w); - break; - } - } else { - // For positive sublayers, we go above all windows in the same sublayer. - if (wSublayer > sublayer) { - addWindowToListBefore(win, w); - break; - } - } - } - if (i >= wCount) { - if (sublayer < 0) { - addWindowToListBefore(win, parentWindow); - } else { - addWindowToListAfter(win, - largestSublayer >= 0 ? windowWithLargestSublayer : parentWindow); - } + if (mTmpWindow == null) { + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows."); + return null; } + return mTmpWindow; } /** Updates the layer assignment of windows on this display. */ void assignWindowLayers(boolean setLayoutNeeded) { - mLayersController.assignWindowLayers(mWindows.getReadOnly()); + mLayersController.assignWindowLayers(this); if (setLayoutNeeded) { setLayoutNeeded(); } } - void adjustWallpaperWindows() { - if (mWallpaperController.adjustWallpaperWindows(mWindows.getReadOnly())) { - assignWindowLayers(true /*setLayoutNeeded*/); - } - } - - /** - * Z-orders the display window list so that: - * <ul> - * <li>Any windows that are currently below the wallpaper window stay below the wallpaper - * window. - * <li>Exiting application windows are at the bottom, but above the wallpaper window. - * <li>All other application windows are above the exiting application windows and ordered based - * on the ordering of their stacks and tasks on the display. - * <li>Non-application windows are at the very top. - * </ul> - * <p> - * NOTE: This isn't a complete picture of what the user see. Further manipulation of the window - * surface layering is done in {@link WindowLayersController}. - */ - void rebuildAppWindowList() { - int count = mWindows.size(); - int i; - int lastBelow = -1; - int numRemoved = 0; - - if (mRebuildTmp.length < count) { - mRebuildTmp = new WindowState[count + 10]; - } - - // First remove all existing app windows. - i = 0; - while (i < count) { - final WindowState w = mWindows.get(i); - if (w.mAppToken != null) { - final WindowState win = mWindows.remove(i); - win.mRebuilding = true; - mRebuildTmp[numRemoved] = win; - mService.mWindowsChanged = true; - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Rebuild removing window: " + win); - count--; - numRemoved++; - continue; - } else if (lastBelow == i-1) { - if (w.mAttrs.type == TYPE_WALLPAPER) { - lastBelow = i; - } - } - i++; - } - - // Keep whatever windows were below the app windows still below, by skipping them. - lastBelow++; - i = lastBelow; - - // First add all of the exiting app tokens... these are no longer in the main app list, - // but still have windows shown. We put them in the back because now that the animation is - // over we no longer will care about them. - final int numStacks = mTaskStackContainers.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - AppTokenList exitingAppTokens = mTaskStackContainers.get(stackNdx).mExitingAppTokens; - int NT = exitingAppTokens.size(); - for (int j = 0; j < NT; j++) { - i = exitingAppTokens.get(j).rebuildWindowListUnchecked(i); - } - } - - // And add in the still active app tokens in Z order. - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - i = mTaskStackContainers.get(stackNdx).rebuildWindowList(i); - } - - i -= lastBelow; - if (i != numRemoved) { - setLayoutNeeded(); - Slog.w(TAG_WM, "On display=" + mDisplayId + " Rebuild removed " + numRemoved - + " windows but added " + i + " rebuildAppWindowListLocked() " - + " callers=" + Debug.getCallers(10)); - for (i = 0; i < numRemoved; i++) { - WindowState ws = mRebuildTmp[i]; - if (ws.mRebuilding) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new FastPrintWriter(sw, false, 1024); - ws.dump(pw, "", true); - pw.flush(); - Slog.w(TAG_WM, "This window was lost: " + ws); - Slog.w(TAG_WM, sw.toString()); - ws.mWinAnimator.destroySurfaceLocked(); - } - } - Slog.w(TAG_WM, "Current window hierarchy:"); - dumpChildrenNames(); - Slog.w(TAG_WM, "Final window list:"); - dumpWindows(); - } - Arrays.fill(mRebuildTmp, null); - } - - /** Rebuilds the display's window list and does a relayout if something changed. */ - void rebuildAppWindowsAndLayoutIfNeeded() { - mTmpWindows.clear(); - mTmpWindows.addAll(mWindows); - - rebuildAppWindowList(); - - // Set displayContent.mLayoutNeeded if window order changed. - final int tmpSize = mTmpWindows.size(); - final int winSize = mWindows.size(); - int tmpNdx = 0, winNdx = 0; - while (tmpNdx < tmpSize && winNdx < winSize) { - // Skip over all exiting windows, they've been moved out of order. - WindowState tmp; - do { - tmp = mTmpWindows.get(tmpNdx++); - } while (tmpNdx < tmpSize && tmp.mAppToken != null && tmp.mAppToken.mIsExiting); - - WindowState win; - do { - win = mWindows.get(winNdx++); - } while (winNdx < winSize && win.mAppToken != null && win.mAppToken.mIsExiting); - - if (tmp != win) { - // Window order changed. - setLayoutNeeded(); - break; - } - } - if (tmpNdx != winNdx) { - // One list was different from the other. - setLayoutNeeded(); - } - mTmpWindows.clear(); + void layoutAndAssignWindowLayersIfNeeded() { + mService.mWindowsChanged = true; + setLayoutNeeded(); if (!mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/)) { @@ -1549,321 +1150,69 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mService.mInputMonitor.updateInputWindowsLw(false /*force*/); } - void updateInputWindows(InputMonitor inputMonitor, WindowState inputFocus, boolean inDrag) { - final InputConsumerImpl navInputConsumer = - mService.mInputMonitor.getInputConsumer(INPUT_CONSUMER_NAVIGATION, mDisplayId); - final InputConsumerImpl pipInputConsumer = - mService.mInputMonitor.getInputConsumer(INPUT_CONSUMER_PIP, mDisplayId); - final InputConsumerImpl wallpaperInputConsumer = - mService.mInputMonitor.getInputConsumer(INPUT_CONSUMER_WALLPAPER, mDisplayId); - boolean addInputConsumerHandle = navInputConsumer != null; - boolean addPipInputConsumerHandle = pipInputConsumer != null; - boolean addWallpaperInputConsumerHandle = wallpaperInputConsumer != null; - final Rect pipTouchableBounds = addPipInputConsumerHandle ? new Rect() : null; - boolean disableWallpaperTouchEvents = false; - - for (int winNdx = mWindows.size() - 1; winNdx >= 0; --winNdx) { - final WindowState child = mWindows.get(winNdx); - final InputChannel inputChannel = child.mInputChannel; - final InputWindowHandle inputWindowHandle = child.mInputWindowHandle; - if (inputChannel == null || inputWindowHandle == null || child.mRemoved - || child.isAdjustedForMinimizedDock()) { - // Skip this window because it cannot possibly receive input. - continue; - } - - if (addPipInputConsumerHandle - && child.getStackId() == PINNED_STACK_ID - && inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer) { - // Update the bounds of the Pip input consumer to match the Pinned stack - child.getStack().getBounds(pipTouchableBounds); - pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds); - inputMonitor.addInputWindowHandle(pipInputConsumer.mWindowHandle); - addPipInputConsumerHandle = false; - } - - if (addInputConsumerHandle - && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) { - inputMonitor.addInputWindowHandle(navInputConsumer.mWindowHandle); - addInputConsumerHandle = false; - } - - if (addWallpaperInputConsumerHandle) { - if (child.mAttrs.type == TYPE_WALLPAPER && child.isVisibleLw()) { - // Add the wallpaper input consumer above the first visible wallpaper. - inputMonitor.addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); - addWallpaperInputConsumerHandle = false; - } - } - - final int flags = child.mAttrs.flags; - final int privateFlags = child.mAttrs.privateFlags; - final int type = child.mAttrs.type; - - final boolean hasFocus = child == inputFocus; - final boolean isVisible = child.isVisibleLw(); - if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) { - disableWallpaperTouchEvents = true; - } - final boolean hasWallpaper = mWallpaperController.isWallpaperTarget(child) - && (privateFlags & PRIVATE_FLAG_KEYGUARD) == 0 - && !disableWallpaperTouchEvents; - - // If there's a drag in progress and 'child' is a potential drop target, - // make sure it's been told about the drag - if (inDrag && isVisible && isDefaultDisplay) { - mService.mDragState.sendDragStartedIfNeededLw(child); - } - - inputMonitor.addInputWindowHandle( - inputWindowHandle, child, flags, type, isVisible, hasFocus, hasWallpaper); - } - - if (addWallpaperInputConsumerHandle) { - // No visible wallpaper found, add the wallpaper input consumer at the end. - inputMonitor.addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); - } - } - /** Returns true if a leaked surface was destroyed */ boolean destroyLeakedSurfaces() { - boolean leakedSurface = false; - final int numWindows = mWindows.size(); - for (int winNdx = 0; winNdx < numWindows; ++winNdx) { - final WindowState ws = mWindows.get(winNdx); - final WindowStateAnimator wsa = ws.mWinAnimator; + // Used to indicate that a surface was leaked. + mTmpWindow = null; + forAllWindows(w -> { + final WindowStateAnimator wsa = w.mWinAnimator; if (wsa.mSurfaceController == null) { - continue; + return; } if (!mService.mSessions.contains(wsa.mSession)) { Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): " - + ws + " surface=" + wsa.mSurfaceController - + " token=" + ws.mToken - + " pid=" + ws.mSession.mPid - + " uid=" + ws.mSession.mUid); + + w + " surface=" + wsa.mSurfaceController + + " token=" + w.mToken + + " pid=" + w.mSession.mPid + + " uid=" + w.mSession.mUid); wsa.destroySurface(); - mService.mForceRemoves.add(ws); - leakedSurface = true; - } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) { + mService.mForceRemoves.add(w); + mTmpWindow = w; + } else if (w.mAppToken != null && w.mAppToken.clientHidden) { Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): " - + ws + " surface=" + wsa.mSurfaceController - + " token=" + ws.mAppToken - + " saved=" + ws.hasSavedSurface()); - if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false); + + w + " surface=" + wsa.mSurfaceController + + " token=" + w.mAppToken + + " saved=" + w.hasSavedSurface()); + if (SHOW_TRANSACTIONS) logSurface(w, "LEAK DESTROY", false); wsa.destroySurface(); - leakedSurface = true; + mTmpWindow = w; } - } - - return leakedSurface; - } - - /** Return the list of Windows on this display associated with the input token. */ - WindowList getTokenWindowsOnDisplay(WindowToken token) { - final WindowList windowList = new WindowList(); - final int count = mWindows.size(); - for (int i = 0; i < count; i++) { - final WindowState win = mWindows.get(i); - if (win.mToken == token) { - windowList.add(win); - } - } - return windowList; - } + }, false /* traverseTopToBottom */); - private void reAddToWindowList(WindowState win) { - win.mToken.addWindow(win); - // This is a hack to get all of the child windows added as well at the right position. Child - // windows should be rare and this case should be rare, so it shouldn't be that big a deal. - int wpos = mWindows.indexOf(win); - if (wpos >= 0) { - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "ReAdd removing from " + wpos + ": " + win); - mWindows.remove(wpos); - mService.mWindowsChanged = true; - win.reAddWindow(wpos); - } - } - - void moveInputMethodDialogs(int pos) { - ArrayList<WindowState> dialogs = mService.mInputMethodDialogs; - - final int N = dialogs.size(); - if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Removing " + N + " dialogs w/pos=" + pos); - for (int i = 0; i < N; i++) { - pos = removeWindowAndChildrenFromWindowList(dialogs.get(i), pos); - } - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "Window list w/pos=" + pos); - logWindowList(mWindows, " "); - } - - WindowState ime = mService.mInputMethodWindow; - if (pos >= 0) { - // Skip windows owned by the input method. - if (ime != null) { - while (pos < mWindows.size()) { - WindowState wp = mWindows.get(pos); - if (wp == ime || wp.getParentWindow() == ime) { - pos++; - continue; - } - break; - } - } - if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Adding " + N + " dialogs at pos=" + pos); - for (int i=0; i<N; i++) { - WindowState win = dialogs.get(i); - pos = win.reAddWindow(pos); - } - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "Final window list:"); - logWindowList(mWindows, " "); - } - return; - } - for (int i=0; i<N; i++) { - WindowState win = dialogs.get(i); - reAddToWindowList(win); - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "No IM target, final list:"); - logWindowList(mWindows, " "); - } - } - } - - boolean moveInputMethodWindowsIfNeeded(boolean needAssignLayers) { - final WindowState imWin = mService.mInputMethodWindow; - final int DN = mService.mInputMethodDialogs.size(); - if (imWin == null && DN == 0) { - return false; - } - - // TODO(multidisplay): IMEs are only supported on the default display. - int imPos = findDesiredInputMethodWindowIndex(true); - if (imPos >= 0) { - // In this case, the input method windows are to be placed - // immediately above the window they are targeting. - - // First check to see if the input method windows are already - // located here, and contiguous. - final int N = mWindows.size(); - final WindowState firstImWin = imPos < N ? mWindows.get(imPos) : null; - - // Figure out the actual input method window that should be - // at the bottom of their stack. - WindowState baseImWin = imWin != null ? imWin : mService.mInputMethodDialogs.get(0); - final WindowState cw = baseImWin.getBottomChild(); - if (cw != null && cw.mSubLayer < 0) { - baseImWin = cw; - } - - if (firstImWin == baseImWin) { - // The windows haven't moved... but are they still contiguous? - // First find the top IM window. - int pos = imPos+1; - while (pos < N) { - if (!(mWindows.get(pos)).mIsImWindow) { - break; - } - pos++; - } - pos++; - // Now there should be no more input method windows above. - while (pos < N) { - if ((mWindows.get(pos)).mIsImWindow) { - break; - } - pos++; - } - if (pos >= N) { - return false; - } - } - - if (imWin != null) { - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "Moving IM from " + imPos); - logWindowList(mWindows, " "); - } - imPos = removeWindowAndChildrenFromWindowList(imWin, imPos); - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "List after removing with new pos " + imPos + ":"); - logWindowList(mWindows, " "); - } - imWin.reAddWindow(imPos); - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "List after moving IM to " + imPos + ":"); - logWindowList(mWindows, " "); - } - if (DN > 0) moveInputMethodDialogs(imPos+1); - } else { - moveInputMethodDialogs(imPos); - } - - } else { - // In this case, the input method windows go in a fixed layer, - // because they aren't currently associated with a focus window. - - if (imWin != null) { - if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Moving IM from " + imPos); - removeWindowAndChildrenFromWindowList(imWin, 0); - reAddToWindowList(imWin); - if (DEBUG_INPUT_METHOD) { - Slog.v(TAG_WM, "List with no IM target:"); - logWindowList(mWindows, " "); - } - if (DN > 0) moveInputMethodDialogs(-1); - } else { - moveInputMethodDialogs(-1); - } - - } - - if (needAssignLayers) { - assignWindowLayers(false /* setLayoutNeeded */); - } - - return true; + return mTmpWindow != null; } /** - * Dig through the WindowStates and find the one that the Input Method will target. - * @param willMove - * @return The index+1 in mWindows of the discovered target. + * Determine and return the window that should be the IME target. + * @param updateImeTarget If true the system IME target will be updated to match what we found. + * @return The window that should be used as the IME target or null if there isn't any. */ - int findDesiredInputMethodWindowIndex(boolean willMove) { + WindowState computeImeTarget(boolean updateImeTarget) { // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the // same display. Or even when the current IME/target are not on the same screen as the next // IME/target. For now only look for input windows on the main screen. - WindowState w = null; - int i; - for (i = mWindows.size() - 1; i >= 0; --i) { - final WindowState win = mWindows.get(i); - - if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG_WM, "Checking window @" + i - + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags)); - if (canBeImeTarget(win)) { - w = win; - //Slog.i(TAG_WM, "Putting input method here!"); - - // Yet more tricksyness! If this window is a "starting" window, we do actually want - // to be on top of it, but it is not -really- where input will go. So if the caller - // is not actually looking to move the IME, look down below for a real window to - // target... - if (!willMove && w.mAttrs.type == TYPE_APPLICATION_STARTING && i > 0) { - final WindowState wb = mWindows.get(i-1); - if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) { - i--; - w = wb; - } + WindowState target = getWindow(w -> { + if (DEBUG_INPUT_METHOD && updateImeTarget) Slog.i(TAG_WM, "Checking window @" + + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags)); + return w.canBeImeTarget(); + }); + + + // Yet more tricksyness! If this window is a "starting" window, we do actually want + // to be on top of it, but it is not -really- where input will go. So look down below + // for a real window to target... + if (target != null && target.mAttrs.type == TYPE_APPLICATION_STARTING) { + final AppWindowToken token = target.mAppToken; + if (token != null) { + final WindowState betterTarget = token.getImeTargetBelowWindow(target); + if (betterTarget != null) { + target = betterTarget; } - break; } } - // Now w is either mWindows[0] or an IME (or null if mWindows is empty). - - if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG_WM, "Proposed new IME target: " + w); + if (DEBUG_INPUT_METHOD && updateImeTarget) Slog.v(TAG_WM, + "Proposed new IME target: " + target); // Now, a special case -- if the last target's window is in the process of exiting, and is // above the new target, keep on the last target to avoid flicker. Consider for example a @@ -1871,18 +1220,28 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // until it is completely gone so it doesn't drop behind the dialog or its full-screen // scrim. final WindowState curTarget = mService.mInputMethodTarget; - if (curTarget != null - && curTarget.isDisplayedLw() - && curTarget.isClosing() - && (w == null || curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) { + if (curTarget != null && curTarget.isDisplayedLw() && curTarget.isClosing() + && (target == null + || curTarget.mWinAnimator.mAnimLayer > target.mWinAnimator.mAnimLayer)) { if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Current target higher, not changing"); - return mWindows.indexOf(curTarget) + 1; + return curTarget; } - if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Desired input method target=" - + w + " willMove=" + willMove); + if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Desired input method target=" + target + + " updateImeTarget=" + updateImeTarget); + + if (target == null) { + if (updateImeTarget) { + if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + + " to null." + (SHOW_STACK_CRAWLS ? " Callers=" + + Debug.getCallers(4) : "")); + setInputMethodTarget(null, mService.mInputMethodTargetWaitingAnim, 0); + } + + return null; + } - if (willMove && w != null) { + if (updateImeTarget) { AppWindowToken token = curTarget == null ? null : curTarget.mAppToken; if (token != null) { @@ -1890,24 +1249,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // to look at all windows below the current target that are in this app, finding the // highest visible one in layering. WindowState highestTarget = null; - int highestPos = 0; if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) { - WindowList curWindows = token.getDisplayContent().mWindows; - int pos = curWindows.indexOf(curTarget); - while (pos >= 0) { - WindowState win = curWindows.get(pos); - if (win.mAppToken != token) { - break; - } - if (!win.mRemoved) { - if (highestTarget == null || win.mWinAnimator.mAnimLayer > - highestTarget.mWinAnimator.mAnimLayer) { - highestTarget = win; - highestPos = pos; - } - } - pos--; - } + highestTarget = token.getHighestAnimLayerWindow(curTarget); } if (highestTarget != null) { @@ -1915,121 +1258,76 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, appTransition + " " + highestTarget + " animating=" + highestTarget.mWinAnimator.isAnimationSet() + " layer=" + highestTarget.mWinAnimator.mAnimLayer - + " new layer=" + w.mWinAnimator.mAnimLayer); + + " new layer=" + target.mWinAnimator.mAnimLayer); if (appTransition.isTransitionSet()) { // If we are currently setting up for an animation, hold everything until we // can find out what will happen. - mService.mInputMethodTargetWaitingAnim = true; - mService.mInputMethodTarget = highestTarget; - return highestPos + 1; + setInputMethodTarget(highestTarget, true, mInputMethodAnimLayerAdjustment); + return highestTarget; } else if (highestTarget.mWinAnimator.isAnimationSet() && - highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { + highestTarget.mWinAnimator.mAnimLayer > target.mWinAnimator.mAnimLayer) { // If the window we are currently targeting is involved with an animation, // and it is on top of the next target we will be over, then hold off on // moving until that is done. - mService.mInputMethodTargetWaitingAnim = true; - mService.mInputMethodTarget = highestTarget; - return highestPos + 1; + setInputMethodTarget(highestTarget, true, mInputMethodAnimLayerAdjustment); + return highestTarget; } } } - } - - //Slog.i(TAG_WM, "Placing input method @" + (i+1)); - if (w != null) { - if (willMove) { - if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to " - + w + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); - mService.mInputMethodTarget = w; - mService.mInputMethodTargetWaitingAnim = false; - if (w.mAppToken != null) { - setInputMethodAnimLayerAdjustment( - w.mAppToken.mAppAnimator.animLayerAdjustment); - } else { - setInputMethodAnimLayerAdjustment(0); - } - } - // If the docked divider is visible, we still need to go through this whole excercise to - // find the appropriate input method target (used for animations and dialog - // adjustments), but for purposes of Z ordering we simply wish to place it above the - // docked divider. Unless it is already above the divider. - final WindowState dockedDivider = mDividerControllerLocked.getWindow(); - if (dockedDivider != null && dockedDivider.isVisibleLw()) { - int dividerIndex = mWindows.indexOf(dockedDivider); - if (dividerIndex > 0 && dividerIndex > i) { - return dividerIndex + 1; - } - } - return i+1; - } - if (willMove) { - if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget - + " to null." + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); - mService.mInputMethodTarget = null; - setInputMethodAnimLayerAdjustment(0); + if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to " + + target + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); + setInputMethodTarget(target, false, target.mAppToken != null + ? target.mAppToken.mAppAnimator.animLayerAdjustment : 0); } - return -1; - } - private static boolean canBeImeTarget(WindowState w) { - final int fl = w.mAttrs.flags & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); - final int type = w.mAttrs.type; + return target; + } - if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM) - && type != TYPE_APPLICATION_STARTING) { - return false; + private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim, int layerAdj) { + if (target == mService.mInputMethodTarget + && mService.mInputMethodTargetWaitingAnim == targetWaitingAnim + && mInputMethodAnimLayerAdjustment == layerAdj) { + return; } - if (DEBUG_INPUT_METHOD) { - Slog.i(TAG_WM, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding()); - if (!w.isVisibleOrAdding()) { - Slog.i(TAG_WM, " mSurfaceController=" + w.mWinAnimator.mSurfaceController - + " relayoutCalled=" + w.mRelayoutCalled - + " viewVis=" + w.mViewVisibility - + " policyVis=" + w.mPolicyVisibility - + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim - + " parentHidden=" + w.isParentWindowHidden() - + " exiting=" + w.mAnimatingExit + " destroying=" + w.mDestroying); - if (w.mAppToken != null) { - Slog.i(TAG_WM, " mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested); - } - } - } - return w.isVisibleOrAdding(); + mService.mInputMethodTarget = target; + mService.mInputMethodTargetWaitingAnim = targetWaitingAnim; + setInputMethodAnimLayerAdjustment(layerAdj); + assignWindowLayers(false /* setLayoutNeeded */); } - private void logWindowList(final WindowList windows, String prefix) { - int N = windows.size(); - while (N > 0) { - N--; - Slog.v(TAG_WM, prefix + "#" + N + ": " + windows.get(N)); + boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) { + if (top.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) { + return top.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE; } - } - boolean getNeedsMenu(WindowState win, WindowManagerPolicy.WindowState bottom) { - int index = -1; - while (true) { - if (win.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) { - return win.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE; + // Used to indicate we have reached the first window in the range we are interested in. + mTmpWindow = null; + + // TODO: Figure-out a more efficient way to do this. + final WindowState candidate = getWindow(w -> { + if (w == top) { + // Reached the first window in the range we are interested in. + mTmpWindow = w; } - // If we reached the bottom of the range of windows we are considering, - // assume no menu is needed. - if (win == bottom) { + if (mTmpWindow == null) { return false; } - // The current window hasn't specified whether menu key is needed; look behind it. - // First, we may need to determine the starting position. - if (index < 0) { - index = mWindows.indexOf(win); + + if (w.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) { + return true; } - index--; - if (index < 0) { - return false; + // If we reached the bottom of the range of windows we are considering, + // assume no menu is needed. + if (w == bottom) { + return true; } - win = mWindows.get(index); - } + return false; + }); + + return candidate != null && candidate.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE; } void setLayoutNeeded() { @@ -2046,85 +1344,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mLayoutNeeded; } - private void addAppWindowExisting(WindowState win, WindowList tokenWindowList) { - - // If this application has existing windows, we simply place the new window on top of - // them... but keep the starting window on top. - if (win.mAttrs.type == TYPE_BASE_APPLICATION) { - // Base windows go behind everything else. - final WindowState lowestWindow = tokenWindowList.get(0); - addWindowToListBefore(win, lowestWindow); - } else { - final AppWindowToken atoken = win.mAppToken; - final int windowListPos = tokenWindowList.size(); - final WindowState lastWindow = tokenWindowList.get(windowListPos - 1); - if (atoken != null && lastWindow == atoken.startingWindow) { - addWindowToListBefore(win, lastWindow); - } else { - int newIdx = findIdxBasedOnAppTokens(win); - // There is a window above this one associated with the same apptoken note that the - // window could be a floating window that was created later or a window at the top - // of the list of windows associated with this token. - if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " - + mWindows.size()); - mWindows.add(newIdx + 1, win); - mService.mWindowsChanged = true; - } - } - } - - /** Places the first input window after the second input window in the window list. */ - private void addWindowToListAfter(WindowState first, WindowState second) { - final int i = mWindows.indexOf(second); - if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Adding window " + this + " at " + (i + 1) + " of " + mWindows.size() - + " (after " + second + ")"); - mWindows.add(i + 1, first); - mService.mWindowsChanged = true; - } - - /** Places the first input window before the second input window in the window list. */ - private void addWindowToListBefore(WindowState first, WindowState second) { - int i = mWindows.indexOf(second); - if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Adding window " + this + " at " + i + " of " + mWindows.size() - + " (before " + second + ")"); - if (i < 0) { - Slog.w(TAG_WM, "addWindowToListBefore: Unable to find " + second + " in " + mWindows); - i = 0; - } - mWindows.add(i, first); - mService.mWindowsChanged = true; - } - - /** - * This method finds out the index of a window that has the same app token as win. used for z - * ordering the windows in mWindows - */ - private int findIdxBasedOnAppTokens(WindowState win) { - for(int j = mWindows.size() - 1; j >= 0; j--) { - final WindowState wentry = mWindows.get(j); - if(wentry.mAppToken == win.mAppToken) { - return j; - } - } - return -1; - } - - private void dumpChildrenNames() { - StringBuilder output = new StringBuilder(); - dumpChildrenNames(output, " "); - Slog.v(TAG_WM, output.toString()); - } - - private void dumpWindows() { - Slog.v(TAG_WM, " Display #" + mDisplayId); - for (int winNdx = mWindows.size() - 1; winNdx >= 0; --winNdx) { - Slog.v(TAG_WM, " #" + winNdx + ": " + mWindows.get(winNdx)); - } - } - void dumpTokens(PrintWriter pw, boolean dumpAll) { if (mTokenMap.isEmpty()) { return; @@ -2145,25 +1364,24 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void dumpWindowAnimators(PrintWriter pw, String subPrefix) { - final int count = mWindows.size(); - for (int j = 0; j < count; j++) { - final WindowStateAnimator wAnim = mWindows.get(j).mWinAnimator; - pw.println(subPrefix + "Window #" + j + ": " + wAnim); - } + final int[] index = new int[1]; + forAllWindows(w -> { + final WindowStateAnimator wAnim = w.mWinAnimator; + pw.println(subPrefix + "Window #" + index[0] + ": " + wAnim); + index[0] = index[0] + 1; + }, false /* traverseTopToBottom */); } void enableSurfaceTrace(FileDescriptor fd) { - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState win = mWindows.get(i); - win.mWinAnimator.enableSurfaceTrace(fd); - } + forAllWindows(w -> { + w.mWinAnimator.enableSurfaceTrace(fd); + }, true /* traverseTopToBottom */); } void disableSurfaceTrace() { - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState win = mWindows.get(i); - win.mWinAnimator.disableSurfaceTrace(); - } + forAllWindows(w -> { + w.mWinAnimator.disableSurfaceTrace(); + }, true /* traverseTopToBottom */); } /** @@ -2171,63 +1389,68 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade) { final WindowManagerPolicy policy = mService.mPolicy; - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState window = mWindows.get(i); - if (window.mAppToken == null && policy.canBeHiddenByKeyguardLw(window)) { - window.mWinAnimator.setAnimation( + forAllWindows(w -> { + if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)) { + w.mWinAnimator.setAnimation( policy.createHiddenByKeyguardExit(onWallpaper, goingToShade)); } - } + }, true /* traverseTopToBottom */); } boolean checkWaitingForWindows() { - boolean haveBootMsg = false; - boolean haveApp = false; - // if the wallpaper service is disabled on the device, we're never going to have - // wallpaper, don't bother waiting for it - boolean haveWallpaper = false; - boolean wallpaperEnabled = mService.mContext.getResources().getBoolean( - com.android.internal.R.bool.config_enableWallpaperService) - && !mService.mOnlyCore; - boolean haveKeyguard = true; - final int count = mWindows.size(); - for (int i = 0; i < count; i++) { - final WindowState w = mWindows.get(i); + mHaveBootMsg = false; + mHaveApp = false; + mHaveWallpaper = false; + mHaveKeyguard = true; + + final WindowState visibleWindow = getWindow(w -> { if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { return true; } if (w.isDrawnLw()) { if (w.mAttrs.type == TYPE_BOOT_PROGRESS) { - haveBootMsg = true; + mHaveBootMsg = true; } else if (w.mAttrs.type == TYPE_APPLICATION || w.mAttrs.type == TYPE_DRAWN_APPLICATION) { - haveApp = true; + mHaveApp = true; } else if (w.mAttrs.type == TYPE_WALLPAPER) { - haveWallpaper = true; + mHaveWallpaper = true; } else if (w.mAttrs.type == TYPE_STATUS_BAR) { - haveKeyguard = mService.mPolicy.isKeyguardDrawnLw(); + mHaveKeyguard = mService.mPolicy.isKeyguardDrawnLw(); } } + return false; + }); + + if (visibleWindow != null) { + // We have a visible window. + return true; } + // if the wallpaper service is disabled on the device, we're never going to have + // wallpaper, don't bother waiting for it + boolean wallpaperEnabled = mService.mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enableWallpaperService) + && !mService.mOnlyCore; + if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******** booted=" + mService.mSystemBooted + " msg=" + mService.mShowingBootMessages - + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp - + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled - + " haveKeyguard=" + haveKeyguard); + + " haveBoot=" + mHaveBootMsg + " haveApp=" + mHaveApp + + " haveWall=" + mHaveWallpaper + " wallEnabled=" + wallpaperEnabled + + " haveKeyguard=" + mHaveKeyguard); // If we are turning on the screen to show the boot message, don't do it until the boot // message is actually displayed. - if (!mService.mSystemBooted && !haveBootMsg) { + if (!mService.mSystemBooted && !mHaveBootMsg) { return true; } // If we are turning on the screen after the boot is completed normally, don't do so until // we have the application and wallpaper. - if (mService.mSystemBooted && ((!haveApp && !haveKeyguard) || - (wallpaperEnabled && !haveWallpaper))) { + if (mService.mSystemBooted + && ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) { return true; } @@ -2235,10 +1458,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void updateWindowsForAnimator(WindowAnimator animator) { - final WallpaperController wallpaperController = mWallpaperController; - for (int i = mWindows.size() - 1; i >= 0; i--) { - WindowState win = mWindows.get(i); - WindowStateAnimator winAnimator = win.mWinAnimator; + forAllWindows(w -> { + WindowStateAnimator winAnimator = w.mWinAnimator; if (winAnimator.hasSurface()) { final boolean wasAnimating = winAnimator.mWasAnimating; final boolean nowAnimating = winAnimator.stepAnimationLocked(animator.mCurrentTime); @@ -2246,10 +1467,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo animator.orAnimating(nowAnimating); if (DEBUG_WALLPAPER) Slog.v(TAG, - win + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating); + w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating); if (wasAnimating && !winAnimator.mAnimating - && wallpaperController.isWallpaperTarget(win)) { + && mWallpaperController.isWallpaperTarget(w)) { animator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; if (DEBUG_LAYOUT_REPEATS) { @@ -2259,10 +1480,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - final AppWindowToken atoken = win.mAppToken; + final AppWindowToken atoken = w.mAppToken; if (winAnimator.mDrawState == READY_TO_SHOW) { if (atoken == null || atoken.allDrawn) { - if (win.performShowLocked()) { + if (w.performShowLocked()) { pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; if (DEBUG_LAYOUT_REPEATS) { mService.mWindowPlacerLocked.debugLayoutRepeats( @@ -2281,23 +1502,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo appAnimator.thumbnailLayer = winAnimator.mAnimLayer; } } - } // end forall windows + }, true /* traverseTopToBottom */); } void updateWallpaperForAnimator(WindowAnimator animator) { resetAnimationBackgroundAnimator(); - final WindowList windows = mWindows; - WindowState detachedWallpaper = null; + // Used to indicate a detached wallpaper. + mTmpWindow = null; - for (int i = windows.size() - 1; i >= 0; i--) { - final WindowState win = windows.get(i); - final WindowStateAnimator winAnimator = win.mWinAnimator; + forAllWindows(w -> { + final WindowStateAnimator winAnimator = w.mWinAnimator; if (winAnimator.mSurfaceController == null || !winAnimator.hasSurface()) { - continue; + return; } - final int flags = win.mAttrs.flags; + final int flags = w.mAttrs.flags; // If this window is animating, make a note that we have an animating window and take // care of a request to run a detached wallpaper animation. @@ -2305,11 +1525,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (winAnimator.mAnimation != null) { if ((flags & FLAG_SHOW_WALLPAPER) != 0 && winAnimator.mAnimation.getDetachWallpaper()) { - detachedWallpaper = win; + mTmpWindow = w; } final int color = winAnimator.mAnimation.getBackgroundColor(); if (color != 0) { - final TaskStack stack = win.getStack(); + final TaskStack stack = w.getStack(); if (stack != null) { stack.setAnimationBackground(winAnimator, color); } @@ -2325,64 +1545,45 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo && appAnimator.animating) { if ((flags & FLAG_SHOW_WALLPAPER) != 0 && appAnimator.animation.getDetachWallpaper()) { - detachedWallpaper = win; + mTmpWindow = w; } final int color = appAnimator.animation.getBackgroundColor(); if (color != 0) { - final TaskStack stack = win.getStack(); + final TaskStack stack = w.getStack(); if (stack != null) { stack.setAnimationBackground(winAnimator, color); } } } - } // end forall windows + }, true /* traverseTopToBottom */); - if (animator.mWindowDetachedWallpaper != detachedWallpaper) { + if (animator.mWindowDetachedWallpaper != mTmpWindow) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Detached wallpaper changed from " - + animator.mWindowDetachedWallpaper + " to " + detachedWallpaper); - animator.mWindowDetachedWallpaper = detachedWallpaper; + + animator.mWindowDetachedWallpaper + " to " + mTmpWindow); + animator.mWindowDetachedWallpaper = mTmpWindow; animator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; } } void prepareWindowSurfaces() { - final int count = mWindows.size(); - for (int j = 0; j < count; j++) { - mWindows.get(j).mWinAnimator.prepareSurfaceLocked(true); - } + forAllWindows(w -> { + w.mWinAnimator.prepareSurfaceLocked(true); + }, false /* traverseTopToBottom */); } boolean inputMethodClientHasFocus(IInputMethodClient client) { - // The focus for the client is the window immediately below where we would place the input - // method window. - int idx = findDesiredInputMethodWindowIndex(false); - if (idx <= 0) { + final WindowState imFocus = computeImeTarget(false /* updateImeTarget */); + if (imFocus == null) { return false; } - WindowState imFocus = mWindows.get(idx - 1); if (DEBUG_INPUT_METHOD) { Slog.i(TAG_WM, "Desired input method target: " + imFocus); Slog.i(TAG_WM, "Current focus: " + mService.mCurrentFocus); Slog.i(TAG_WM, "Last focus: " + mService.mLastFocus); } - if (imFocus == null) { - return false; - } - - // This may be a starting window, in which case we still want to count it as okay. - if (imFocus.mAttrs.type == TYPE_APPLICATION_STARTING && imFocus.mAppToken != null) { - // The client has definitely started, so it really should have a window in this app - // token. Let's look for it. - final WindowState w = imFocus.mAppToken.getFirstNonStartingWindow(); - if (w != null) { - if (DEBUG_INPUT_METHOD) Slog.i(TAG_WM, "Switching to real app window: " + w); - imFocus = w; - } - } - final IInputMethodClient imeClient = imFocus.mSession.mClient; if (DEBUG_INPUT_METHOD) { @@ -2397,83 +1598,63 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } boolean hasSecureWindowOnScreen() { - for (int i = mWindows.size() - 1; i >= 0; --i) { - final WindowState ws = mWindows.get(i); - if (ws.isOnScreen() && (ws.mAttrs.flags & FLAG_SECURE) != 0) { - return true; - } - } - return false; + final WindowState win = getWindow( + w -> w.isOnScreen() && (w.mAttrs.flags & FLAG_SECURE) != 0); + return win != null; } void updateSystemUiVisibility(int visibility, int globalDiff) { - for (int i = mWindows.size() - 1; i >= 0; --i) { - final WindowState ws = mWindows.get(i); + forAllWindows(w -> { try { - int curValue = ws.mSystemUiVisibility; - int diff = (curValue ^ visibility) & globalDiff; - int newValue = (curValue & ~diff) | (visibility & diff); + final int curValue = w.mSystemUiVisibility; + final int diff = (curValue ^ visibility) & globalDiff; + final int newValue = (curValue & ~diff) | (visibility & diff); if (newValue != curValue) { - ws.mSeq++; - ws.mSystemUiVisibility = newValue; + w.mSeq++; + w.mSystemUiVisibility = newValue; } - if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) { - ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq, + if (newValue != curValue || w.mAttrs.hasSystemUiListeners) { + w.mClient.dispatchSystemUiVisibilityChanged(w.mSeq, visibility, newValue, diff); } } catch (RemoteException e) { // so sorry } - } + }, true /* traverseTopToBottom */); } void onWindowFreezeTimeout() { Slog.w(TAG_WM, "Window freeze timeout expired."); mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT; - for (int i = mWindows.size() - 1; i >= 0; --i) { - final WindowState w = mWindows.get(i); + + forAllWindows(w -> { if (!w.mOrientationChanging) { - continue; + return; } w.mOrientationChanging = false; w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime() - mService.mDisplayFreezeTime); Slog.w(TAG_WM, "Force clearing orientation change: " + w); - } + }, true /* traverseTopToBottom */); mService.mWindowPlacerLocked.performSurfacePlacement(); } void waitForAllWindowsDrawn() { final WindowManagerPolicy policy = mService.mPolicy; - for (int winNdx = mWindows.size() - 1; winNdx >= 0; --winNdx) { - final WindowState win = mWindows.get(winNdx); - final boolean keyguard = policy.isKeyguardHostWindow(win.mAttrs); - if (win.isVisibleLw() && (win.mAppToken != null || keyguard)) { - win.mWinAnimator.mDrawState = DRAW_PENDING; + forAllWindows(w -> { + final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs); + if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) { + w.mWinAnimator.mDrawState = DRAW_PENDING; // Force add to mResizingWindows. - win.mLastContentInsets.set(-1, -1, -1, -1); - mService.mWaitingForDrawn.add(win); + w.mLastContentInsets.set(-1, -1, -1, -1); + mService.mWaitingForDrawn.add(w); } - } - } - - ReadOnlyWindowList getReadOnlyWindowList() { - return mWindows.getReadOnly(); - } - - void getWindows(WindowList output) { - output.addAll(mWindows); + }, true /* traverseTopToBottom */); } // TODO: Super crazy long method that should be broken down... boolean applySurfaceChangesTransaction(boolean recoveringMemory) { - boolean focusDisplayed = false; - boolean displayHasContent = false; - float preferredRefreshRate = 0; - int preferredModeId = 0; - - final int dw = mDisplayInfo.logicalWidth; final int dh = mDisplayInfo.logicalHeight; final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked; @@ -2497,7 +1678,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Remove check for default display when there will be support for multiple wallpaper // targets (on different displays). if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) { - adjustWallpaperWindows(); + mWallpaperController.adjustWallpaperWindows(this); } if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) { @@ -2524,55 +1705,59 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (isDefaultDisplay) { mService.mPolicy.beginPostLayoutPolicyLw(dw, dh); - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState w = mWindows.get(i); + forAllWindows(w -> { mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(), mService.mInputMethodTarget); - } + }, true /* traverseTopToBottom */); pendingLayoutChanges |= mService.mPolicy.finishPostLayoutPolicyLw(); if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats( "after finishPostLayoutPolicyLw", pendingLayoutChanges); } } while (pendingLayoutChanges != 0); - RootWindowContainer root = mService.mRoot; - boolean obscured = false; - boolean syswin = false; + final RootWindowContainer root = mService.mRoot; + mTmpApplySurfaceChangesTransactionState.reset(); resetDimming(); // Only used if default window final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty(); - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState w = mWindows.get(i); - final Task task = w.getTask(); - final boolean obscuredChanged = w.mObscured != obscured; + forAllWindows(w -> { + final boolean obscuredChanged = w.mObscured != + mTmpApplySurfaceChangesTransactionState.obscured; // Update effect. - w.mObscured = obscured; - if (!obscured) { + w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured; + if (!mTmpApplySurfaceChangesTransactionState.obscured) { final boolean isDisplayed = w.isDisplayedLw(); if (isDisplayed && w.isObscuringFullscreen(mDisplayInfo)) { // This window completely covers everything behind it, so we want to leave all // of them as undimmed (for performance reasons). root.mObscuringWindow = w; - obscured = true; + mTmpApplySurfaceChangesTransactionState.obscured = true; } - displayHasContent |= root.handleNotObscuredLocked(w, obscured, syswin); + mTmpApplySurfaceChangesTransactionState.displayHasContent |= + root.handleNotObscuredLocked(w, + mTmpApplySurfaceChangesTransactionState.obscured, + mTmpApplySurfaceChangesTransactionState.syswin); if (w.mHasSurface && isDisplayed) { final int type = w.mAttrs.type; if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR || (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - syswin = true; + mTmpApplySurfaceChangesTransactionState.syswin = true; } - if (preferredRefreshRate == 0 && w.mAttrs.preferredRefreshRate != 0) { - preferredRefreshRate = w.mAttrs.preferredRefreshRate; + if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0 + && w.mAttrs.preferredRefreshRate != 0) { + mTmpApplySurfaceChangesTransactionState.preferredRefreshRate + = w.mAttrs.preferredRefreshRate; } - if (preferredModeId == 0 && w.mAttrs.preferredDisplayModeId != 0) { - preferredModeId = w.mAttrs.preferredDisplayModeId; + if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0 + && w.mAttrs.preferredDisplayModeId != 0) { + mTmpApplySurfaceChangesTransactionState.preferredModeId + = w.mAttrs.preferredDisplayModeId; } } } @@ -2645,16 +1830,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus && w.isDisplayedLw()) { - focusDisplayed = true; + mTmpApplySurfaceChangesTransactionState.focusDisplayed = true; } w.updateResizingWindowIfNeeded(); - } + }, true /* traverseTopToBottom */); mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId, - displayHasContent, - preferredRefreshRate, - preferredModeId, + mTmpApplySurfaceChangesTransactionState.displayHasContent, + mTmpApplySurfaceChangesTransactionState.preferredRefreshRate, + mTmpApplySurfaceChangesTransactionState.preferredModeId, true /* inTraversal, must call performTraversalInTrans... below */); stopDimmingIfNeeded(); @@ -2666,7 +1851,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo atoken.updateAllDrawn(this); } - return focusDisplayed; + return mTmpApplySurfaceChangesTransactionState.focusDisplayed; } void performLayout(boolean initial, boolean updateInputWindows) { @@ -2699,110 +1884,110 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (seq < 0) seq = 0; mService.mLayoutSeq = seq; - boolean behindDream = false; + // Used to indicate that we have processed the dream window and all additional windows are + // behind it. + mTmpWindow = null; // First perform layout of any root windows (not attached to another window). - int topAttached = -1; - for (i = mWindows.size() - 1; i >= 0; i--) { - final WindowState win = mWindows.get(i); - + forAllWindows(w -> { // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid // wasting time and funky changes while a window is animating away. - final boolean gone = (behindDream && mService.mPolicy.canBeHiddenByKeyguardLw(win)) - || win.isGoneForLayoutLw(); - - if (DEBUG_LAYOUT && !win.mLayoutAttached) { - Slog.v(TAG, "1ST PASS " + win + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame - + " mLayoutAttached=" + win.mLayoutAttached - + " screen changed=" + win.isConfigChanged()); - final AppWindowToken atoken = win.mAppToken; - if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + win.mViewVisibility - + " mRelayoutCalled=" + win.mRelayoutCalled + " hidden=" + win.mToken.hidden + final boolean gone = (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w)) + || w.isGoneForLayoutLw(); + + if (DEBUG_LAYOUT && !w.mLayoutAttached) { + Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame + + " mLayoutAttached=" + w.mLayoutAttached + + " screen changed=" + w.isConfigChanged()); + final AppWindowToken atoken = w.mAppToken; + if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.hidden + " hiddenRequested=" + (atoken != null && atoken.hiddenRequested) - + " parentHidden=" + win.isParentWindowHidden()); - else Slog.v(TAG, " VIS: mViewVisibility=" + win.mViewVisibility - + " mRelayoutCalled=" + win.mRelayoutCalled + " hidden=" + win.mToken.hidden + + " parentHidden=" + w.isParentWindowHidden()); + else Slog.v(TAG, " VIS: mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.hidden + " hiddenRequested=" + (atoken != null && atoken.hiddenRequested) - + " parentHidden=" + win.isParentWindowHidden()); + + " parentHidden=" + w.isParentWindowHidden()); } // If this view is GONE, then skip it -- keep the current frame, and let the caller know // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, // since that means "perform layout as normal, just don't display"). - if (!gone || !win.mHaveFrame || win.mLayoutNeeded - || ((win.isConfigChanged() || win.setReportResizeHints()) - && !win.isGoneForLayoutLw() && - ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || - (win.mHasSurface && win.mAppToken != null && - win.mAppToken.layoutConfigChanges)))) { - if (!win.mLayoutAttached) { + if (!gone || !w.mHaveFrame || w.mLayoutNeeded + || ((w.isConfigChanged() || w.setReportResizeHints()) + && !w.isGoneForLayoutLw() && + ((w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || + (w.mHasSurface && w.mAppToken != null && + w.mAppToken.layoutConfigChanges)))) { + if (!w.mLayoutAttached) { if (initial) { //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); - win.mContentChanged = false; + w.mContentChanged = false; } - if (win.mAttrs.type == TYPE_DREAM) { + if (w.mAttrs.type == TYPE_DREAM) { // Don't layout windows behind a dream, so that if it does stuff like hide // the status bar we won't get a bad transition when it goes away. - behindDream = true; + mTmpWindow = w; } - win.mLayoutNeeded = false; - win.prelayout(); - mService.mPolicy.layoutWindowLw(win, null); - win.mLayoutSeq = seq; + w.mLayoutNeeded = false; + w.prelayout(); + mService.mPolicy.layoutWindowLw(w, null); + w.mLayoutSeq = mService.mLayoutSeq; // Window frames may have changed. Update dim layer with the new bounds. - final Task task = win.getTask(); + final Task task = w.getTask(); if (task != null) { mDimLayerController.updateDimLayer(task); } - if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + win.mFrame - + " mContainingFrame=" + win.mContainingFrame - + " mDisplayFrame=" + win.mDisplayFrame); - } else { - if (topAttached < 0) topAttached = i; + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame + + " mContainingFrame=" + w.mContainingFrame + + " mDisplayFrame=" + w.mDisplayFrame); } } - } + }, true /* traverseTopToBottom */); - boolean attachedBehindDream = false; + // Used to indicate that we have processed the dream window and all additional attached + // windows are behind it. + final WindowState dreamWin = mTmpWindow; + mTmpWindow = null; // Now perform layout of attached windows, which usually depend on the position of the // window they are attached to. XXX does not deal with windows that are attached to windows // that are themselves attached. - for (i = topAttached; i >= 0; i--) { - final WindowState win = mWindows.get(i); - - if (win.mLayoutAttached) { - if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win + " mHaveFrame=" + win.mHaveFrame - + " mViewVisibility=" + win.mViewVisibility - + " mRelayoutCalled=" + win.mRelayoutCalled); - // If this view is GONE, then skip it -- keep the current frame, and let the caller - // know so they can ignore it if they want. (We do the normal layout for INVISIBLE - // windows, since that means "perform layout as normal, just don't display"). - if (attachedBehindDream && mService.mPolicy.canBeHiddenByKeyguardLw(win)) { - continue; - } - if ((win.mViewVisibility != GONE && win.mRelayoutCalled) || !win.mHaveFrame - || win.mLayoutNeeded) { + forAllWindows(w -> { + if (w.mLayoutAttached) { + if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame + + " mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled); + // If this view is GONE, then skip it -- keep the current frame, and let the + // caller know so they can ignore it if they want. (We do the normal layout for + // INVISIBLE windows, since that means "perform layout as normal, just don't + // display"). + if (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w)) { + return; + } + if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame + || w.mLayoutNeeded) { if (initial) { //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); - win.mContentChanged = false; + w.mContentChanged = false; } - win.mLayoutNeeded = false; - win.prelayout(); - mService.mPolicy.layoutWindowLw(win, win.getParentWindow()); - win.mLayoutSeq = seq; - if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + win.mFrame - + " mContainingFrame=" + win.mContainingFrame - + " mDisplayFrame=" + win.mDisplayFrame); - } - } else if (win.mAttrs.type == TYPE_DREAM) { + w.mLayoutNeeded = false; + w.prelayout(); + mService.mPolicy.layoutWindowLw(w, w.getParentWindow()); + w.mLayoutSeq = mService.mLayoutSeq; + if (DEBUG_LAYOUT) + Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame + + " mContainingFrame=" + w.mContainingFrame + + " mDisplayFrame=" + w.mDisplayFrame); + } + } else if (w.mAttrs.type == TYPE_DREAM) { // Don't layout windows behind a dream, so that if it does stuff like hide the // status bar we won't get a bad transition when it goes away. - attachedBehindDream = behindDream; + mTmpWindow = dreamWin; } - } + }, true /* traverseTopToBottom */); // Window frames may have changed. Tell the input dispatcher about it. mService.mInputMonitor.layoutInputConsumers(dw, dh); @@ -2826,7 +2011,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * @param config of the output bitmap * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot */ - Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height, + Bitmap screenshotApplications(IBinder appToken, int width, int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config, boolean wallpaperOnly) { int dw = mDisplayInfo.logicalWidth; @@ -2839,22 +2024,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo Bitmap bm = null; - int maxLayer = 0; + mScreenshotApplicationState.reset(appToken == null && !wallpaperOnly); final Rect frame = new Rect(); final Rect stackBounds = new Rect(); - boolean screenshotReady; - int minLayer; - if (appToken == null && !wallpaperOnly) { - screenshotReady = true; - minLayer = 0; - } else { - screenshotReady = false; - minLayer = Integer.MAX_VALUE; - } - - WindowState appWin = null; - boolean includeImeInScreenshot; synchronized(mService.mWindowMap) { final AppWindowToken imeTargetAppToken = mService.mInputMethodTarget != null @@ -2875,70 +2048,69 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo synchronized(mService.mWindowMap) { // Figure out the part of the screen that is actually the app. - appWin = null; - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState ws = mWindows.get(i); - if (!ws.mHasSurface) { - continue; + mScreenshotApplicationState.appWin = null; + forAllWindows(w -> { + if (!w.mHasSurface) { + return false; } - if (ws.mLayer >= aboveAppLayer) { - continue; + if (w.mLayer >= aboveAppLayer) { + return false; } - if (wallpaperOnly && !ws.mIsWallpaper) { - continue; + if (wallpaperOnly && !w.mIsWallpaper) { + return false; } - if (ws.mIsImWindow) { + if (w.mIsImWindow) { if (!includeImeInScreenshot) { - continue; + return false; } - } else if (ws.mIsWallpaper) { + } else if (w.mIsWallpaper) { // If this is the wallpaper layer and we're only looking for the wallpaper layer // then the target window state is this one. if (wallpaperOnly) { - appWin = ws; + mScreenshotApplicationState.appWin = w; } - if (appWin == null) { + if (mScreenshotApplicationState.appWin == null) { // We have not ran across the target window yet, so it is probably behind // the wallpaper. This can happen when the keyguard is up and all windows // are moved behind the wallpaper. We don't want to include the wallpaper // layer in the screenshot as it will cover-up the layer of the target // window. - continue; + return false; } // Fall through. The target window is in front of the wallpaper. For this // case we want to include the wallpaper layer in the screenshot because // the target window might have some transparent areas. } else if (appToken != null) { - if (ws.mAppToken == null || ws.mAppToken.token != appToken) { + if (w.mAppToken == null || w.mAppToken.token != appToken) { // This app window is of no interest if it is not associated with the // screenshot app. - continue; + return false; } - appWin = ws; + mScreenshotApplicationState.appWin = w; } // Include this window. - final WindowStateAnimator winAnim = ws.mWinAnimator; + final WindowStateAnimator winAnim = w.mWinAnimator; int layer = winAnim.mSurfaceController.getLayer(); - if (maxLayer < layer) { - maxLayer = layer; + if (mScreenshotApplicationState.maxLayer < layer) { + mScreenshotApplicationState.maxLayer = layer; } - if (minLayer > layer) { - minLayer = layer; + if (mScreenshotApplicationState.minLayer > layer) { + mScreenshotApplicationState.minLayer = layer; } // Don't include wallpaper in bounds calculation - if (!includeFullDisplay && !ws.mIsWallpaper) { - final Rect wf = ws.mFrame; - final Rect cr = ws.mContentInsets; + if (!includeFullDisplay && !w.mIsWallpaper) { + final Rect wf = w.mFrame; + final Rect cr = w.mContentInsets; int left = wf.left + cr.left; int top = wf.top + cr.top; int right = wf.right - cr.right; int bottom = wf.bottom - cr.bottom; frame.union(left, top, right, bottom); - ws.getVisibleBounds(stackBounds); + w.getVisibleBounds(stackBounds); if (!Rect.intersects(frame, stackBounds)) { // Set frame empty if there's no intersection. frame.setEmpty(); @@ -2946,16 +2118,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } final boolean foundTargetWs = - (ws.mAppToken != null && ws.mAppToken.token == appToken) - || (appWin != null && wallpaperOnly); - if (foundTargetWs && ws.isDisplayedLw() && winAnim.getShown()) { - screenshotReady = true; + (w.mAppToken != null && w.mAppToken.token == appToken) + || (mScreenshotApplicationState.appWin != null && wallpaperOnly); + if (foundTargetWs && w.isDisplayedLw() && winAnim.getShown()) { + mScreenshotApplicationState.screenshotReady = true; } - if (ws.isObscuringFullscreen(mDisplayInfo)){ - break; + if (w.isObscuringFullscreen(mDisplayInfo)){ + return true; } - } + return false; + }, true /* traverseTopToBottom */); + + final WindowState appWin = mScreenshotApplicationState.appWin; + final boolean screenshotReady = mScreenshotApplicationState.screenshotReady; + final int maxLayer = mScreenshotApplicationState.maxLayer; + final int minLayer = mScreenshotApplicationState.minLayer; if (appToken != null && appWin == null) { // Can't find a window to snapshot. @@ -3027,14 +2205,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (DEBUG_SCREENSHOT) { Slog.i(TAG_WM, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to " + maxLayer + " appToken=" + appToken); - for (int i = 0; i < mWindows.size(); i++) { - final WindowState win = mWindows.get(i); - final WindowSurfaceController controller = win.mWinAnimator.mSurfaceController; - Slog.i(TAG_WM, win + ": " + win.mLayer - + " animLayer=" + win.mWinAnimator.mAnimLayer + forAllWindows(w -> { + final WindowSurfaceController controller = w.mWinAnimator.mSurfaceController; + Slog.i(TAG_WM, w + ": " + w.mLayer + + " animLayer=" + w.mWinAnimator.mAnimLayer + " surfaceLayer=" + ((controller == null) ? "null" : controller.getLayer())); - } + }, false /* traverseTopToBottom */); } final ScreenRotationAnimation screenRotationAnimation = @@ -3071,6 +2248,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } if (allBlack) { + final WindowState appWin = mScreenshotApplicationState.appWin; + final int maxLayer = mScreenshotApplicationState.maxLayer; + final int minLayer = mScreenshotApplicationState.minLayer; Slog.i(TAG_WM, "Screenshot " + appWin + " was monochrome(" + Integer.toHexString(firstColor) + ")! mSurfaceLayer=" + (appWin != null ? @@ -3111,32 +2291,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void onSeamlessRotationTimeout() { - boolean layoutNeeded = false; - for (int i = mWindows.size() - 1; i >= 0; i--) { - final WindowState w = mWindows.get(i); + // Used to indicate the layout is needed. + mTmpWindow = null; + + forAllWindows(w -> { if (!w.mSeamlesslyRotated) { - continue; + return; } - layoutNeeded = true; + mTmpWindow = w; w.setDisplayLayoutNeeded(); mService.markForSeamlessRotation(w, false); - } + }, true /* traverseTopToBottom */); - if (layoutNeeded) { + if (mTmpWindow != null) { mService.mWindowPlacerLocked.performSurfacePlacement(); } } - static final class GetWindowOnDisplaySearchResult { - boolean reachedToken; - WindowState foundWindow; - - void reset() { - reachedToken = false; - foundWindow = null; - } - } - static final class TaskForResizePointSearchResult { boolean searchDone; Task taskForResize; @@ -3147,6 +2318,39 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + private static final class ApplySurfaceChangesTransactionState { + boolean displayHasContent; + boolean obscured; + boolean syswin; + boolean focusDisplayed; + float preferredRefreshRate; + int preferredModeId; + + void reset() { + displayHasContent = false; + obscured = false; + syswin = false; + focusDisplayed = false; + preferredRefreshRate = 0; + preferredModeId = 0; + } + } + + private static final class ScreenshotApplicationState { + WindowState appWin; + int maxLayer; + int minLayer; + boolean screenshotReady; + + void reset(boolean screenshotReady) { + appWin = null; + maxLayer = 0; + minLayer = 0; + this.screenshotReady = screenshotReady; + minLayer = (screenshotReady) ? 0 : Integer.MAX_VALUE; + } + } + /** * Base class for any direct child window container of {@link #DisplayContent} need to inherit * from. This is mainly a pass through class that allows {@link #DisplayContent} to have @@ -3199,15 +2403,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void removeStackFromDisplay(TaskStack stack) { removeChild(stack); stack.onRemovedFromDisplay(); - // TODO: remove when window list will be gone. - // Manually remove records from window list and tap excluded windows list. - for (int i = mWindows.size() - 1; i >= 0; --i) { - final WindowState windowState = mWindows.get(i); - if (stack == windowState.getStack()) { - mWindows.remove(i); - mTapExcludedWindows.remove(windowState); - } - } } void moveStack(TaskStack stack, boolean toTop) { @@ -3243,6 +2438,59 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } @Override + boolean forAllWindows(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { + if (traverseTopToBottom) { + if (super.forAllWindows(callback, traverseTopToBottom)) { + return true; + } + if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { + return true; + } + } else { + if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { + return true; + } + if (super.forAllWindows(callback, traverseTopToBottom)) { + return true; + } + } + return false; + } + + private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback, + boolean traverseTopToBottom) { + // For legacy reasons we process the TaskStack.mExitingAppTokens first here before the + // app tokens. + // TODO: Investigate if we need to continue to do this or if we can just process them + // in-order. + if (traverseTopToBottom) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens; + for (int j = appTokens.size() - 1; j >= 0; --j) { + if (appTokens.get(j).forAllWindowsUnchecked(callback, + traverseTopToBottom)) { + return true; + } + } + } + } else { + final int count = mChildren.size(); + for (int i = 0; i < count; ++i) { + final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens; + final int appTokensCount = appTokens.size(); + for (int j = 0; j < appTokensCount; j++) { + if (appTokens.get(j).forAllWindowsUnchecked(callback, + traverseTopToBottom)) { + return true; + } + } + } + } + return false; + } + + @Override int getOrientation() { if (mService.isStackVisibleLocked(DOCKED_STACK_ID) || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) { @@ -3299,6 +2547,40 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } @Override + int getOrientation() { + final WindowManagerPolicy policy = mService.mPolicy; + // Find a window requesting orientation. + final WindowState win = getWindow((w) -> { + if (!w.isVisibleLw() || !w.mPolicyVisibilityAfterAnim) { + return false; + } + final int req = w.mAttrs.screenOrientation; + if(req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND + || req == SCREEN_ORIENTATION_UNSET) { + return false; + } + return true; + }); + + if (win != null) { + final int req = win.mAttrs.screenOrientation; + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req); + if (policy.isKeyguardHostWindow(win.mAttrs)) { + mService.mLastKeyguardForcedOrientation = req; + } + return (mService.mLastWindowForcedOrientation = req); + } + + mService.mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED; + + if (policy.isKeyguardShowingAndNotOccluded()) { + return mService.mLastKeyguardForcedOrientation; + } + + return SCREEN_ORIENTATION_UNSET; + } + + @Override String getName() { return mName; } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 6326148d7d86..f8b461eba741 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -206,10 +206,12 @@ public class DockedStackDividerController implements DimLayerUser { config.unset(); config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; config.screenWidthDp = (int) - (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode) / + (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode, + mDisplayContent.getDisplayId()) / mDisplayContent.getDisplayMetrics().density); config.screenHeightDp = (int) - (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode) / + (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode, + mDisplayContent.getDisplayId()) / mDisplayContent.getDisplayMetrics().density); final Context rotationContext = mService.mContext.createConfigurationContext(config); mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm( @@ -266,10 +268,8 @@ public class DockedStackDividerController implements DimLayerUser { } private void resetDragResizingChangeReported() { - final ReadOnlyWindowList windowList = mDisplayContent.getReadOnlyWindowList(); - for (int i = windowList.size() - 1; i >= 0; i--) { - windowList.get(i).resetDragResizingChangeReported(); - } + mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported, + true /* traverseTopToBottom */ ); } void setWindow(WindowState window) { diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java index 7cb6fc3b5430..70478fe677ed 100644 --- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java +++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.content.ClipData; import android.net.Uri; import android.os.Binder; @@ -61,7 +61,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub mActivityToken = activityToken; // Will throw if Activity is not found. - IBinder permissionOwner = ActivityManagerNative.getDefault(). + IBinder permissionOwner = ActivityManager.getService(). getUriPermissionOwnerForActivity(mActivityToken); doTake(permissionOwner); @@ -71,7 +71,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub long origId = Binder.clearCallingIdentity(); try { for (int i = 0; i < mUris.size(); i++) { - ActivityManagerNative.getDefault().grantUriPermissionFromOwner( + ActivityManager.getService().grantUriPermissionFromOwner( permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode, mSourceUserId, mTargetUserId); } @@ -85,7 +85,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub if (mActivityToken != null || mPermissionOwnerToken != null) { return; } - mPermissionOwnerToken = ActivityManagerNative.getDefault().newUriPermissionOwner("drop"); + mPermissionOwnerToken = ActivityManager.getService().newUriPermissionOwner("drop"); mTransientToken = transientToken; mTransientToken.linkToDeath(this, 0); @@ -101,7 +101,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub IBinder permissionOwner = null; if (mActivityToken != null) { try { - permissionOwner = ActivityManagerNative.getDefault(). + permissionOwner = ActivityManager.getService(). getUriPermissionOwnerForActivity(mActivityToken); } catch (Exception e) { // Activity is destroyed, permissions already revoked. @@ -117,7 +117,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub } for (int i = 0; i < mUris.size(); ++i) { - ActivityManagerNative.getDefault().revokeUriPermissionFromOwner( + ActivityManager.getService().revokeUriPermissionFromOwner( permissionOwner, mUris.get(i), mMode, mSourceUserId); } } diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index d52168c46ff3..40b737df6680 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -271,11 +271,9 @@ class DragState { Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); } - final ReadOnlyWindowList windows = mDisplayContent.getReadOnlyWindowList(); - final int N = windows.size(); - for (int i = 0; i < N; i++) { - sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription); - } + mDisplayContent.forAllWindows(w -> { + sendDragStartedLw(w, touchX, touchY, mDataDescription); + }, false /* traverseTopToBottom */ ); } /* helper - send a ACTION_DRAG_STARTED event, if the diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index a8eb75c3ef9c..01d1c30ec0de 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -16,17 +16,22 @@ package com.android.server.wm; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.graphics.Rect; import android.os.Debug; import android.os.Looper; @@ -70,6 +75,10 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { // Array of window handles to provide to the input dispatcher. private InputWindowHandle[] mInputWindowHandles; private int mInputWindowHandleCount; + private boolean mAddInputConsumerHandle; + private boolean mAddPipInputConsumerHandle; + private boolean mAddWallpaperInputConsumerHandle; + private boolean mDisableWallpaperTouchEvents; // Set to true when the first input device configuration change notification // is received to indicate that the input devices are ready. @@ -252,7 +261,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { try { // Notify the activity manager about the timeout and let it decide whether // to abort dispatching or keep waiting. - long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut( + long timeout = ActivityManager.getService().inputDispatchingTimedOut( windowState.mSession.mPid, aboveSystem, reason); if (timeout >= 0) { // The activity manager declined to abort dispatching. @@ -323,12 +332,12 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } } - public void setUpdateInputWindowsNeededLw() { + void setUpdateInputWindowsNeededLw() { mUpdateInputWindowsNeeded = true; } /* Updates the cached window information provided to the input dispatcher. */ - public void updateInputWindowsLw(boolean force) { + void updateInputWindowsLw(boolean force) { if (!force && !mUpdateInputWindowsNeeded) { return; } @@ -372,15 +381,92 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } // Add all windows on the default display. - mService.mRoot.updateInputWindows(this, mInputFocus, inDrag); + updateInputWindows(inDrag); - // Send windows to native code. - mService.mInputManager.setInputWindows(mInputWindowHandles); + if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw"); + } + + private void updateInputWindows(boolean inDrag) { - // Clear the list in preparation for the next round. clearInputWindowHandlesLw(); - if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw"); + // TODO: multi-display + final InputConsumerImpl navInputConsumer = + getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY); + final InputConsumerImpl pipInputConsumer = + getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY); + final InputConsumerImpl wallpaperInputConsumer = + getInputConsumer(INPUT_CONSUMER_WALLPAPER, DEFAULT_DISPLAY); + mAddInputConsumerHandle = navInputConsumer != null; + mAddPipInputConsumerHandle = pipInputConsumer != null; + mAddWallpaperInputConsumerHandle = wallpaperInputConsumer != null; + final Rect pipTouchableBounds = mAddPipInputConsumerHandle ? new Rect() : null; + mDisableWallpaperTouchEvents = false; + + final WallpaperController wallpaperController = mService.mRoot.mWallpaperController; + mService.mRoot.forAllWindows(w -> { + final InputChannel inputChannel = w.mInputChannel; + final InputWindowHandle inputWindowHandle = w.mInputWindowHandle; + if (inputChannel == null || inputWindowHandle == null || w.mRemoved + || w.isAdjustedForMinimizedDock()) { + // Skip this window because it cannot possibly receive input. + return; + } + + if (mAddPipInputConsumerHandle + && w.getStackId() == PINNED_STACK_ID + && inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer) { + // Update the bounds of the Pip input consumer to match the Pinned stack + w.getStack().getBounds(pipTouchableBounds); + pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds); + addInputWindowHandle(pipInputConsumer.mWindowHandle); + mAddPipInputConsumerHandle = false; + } + + if (mAddInputConsumerHandle + && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) { + addInputWindowHandle(navInputConsumer.mWindowHandle); + mAddInputConsumerHandle = false; + } + + if (mAddWallpaperInputConsumerHandle) { + if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisibleLw()) { + // Add the wallpaper input consumer above the first visible wallpaper. + addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); + mAddWallpaperInputConsumerHandle = false; + } + } + + final int flags = w.mAttrs.flags; + final int privateFlags = w.mAttrs.privateFlags; + final int type = w.mAttrs.type; + + final boolean hasFocus = w == mInputFocus; + final boolean isVisible = w.isVisibleLw(); + if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) { + mDisableWallpaperTouchEvents = true; + } + final boolean hasWallpaper = wallpaperController.isWallpaperTarget(w) + && (privateFlags & PRIVATE_FLAG_KEYGUARD) == 0 + && !mDisableWallpaperTouchEvents; + + // If there's a drag in progress and 'child' is a potential drop target, + // make sure it's been told about the drag + if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) { + mService.mDragState.sendDragStartedIfNeededLw(w); + } + + addInputWindowHandle( + inputWindowHandle, w, flags, type, isVisible, hasFocus, hasWallpaper); + }, true /* traverseTopToBottom */); + + if (mAddWallpaperInputConsumerHandle) { + // No visible wallpaper found, add the wallpaper input consumer at the end. + addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); + } + + // Send windows to native code. + mService.mInputManager.setInputWindows(mInputWindowHandles); } /* Notifies that the input device configuration has changed. */ diff --git a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java index 377071d4c46b..2eb186b5973f 100644 --- a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java +++ b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java @@ -19,7 +19,7 @@ package com.android.server.wm; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.Handler; @@ -101,7 +101,7 @@ public class KeyguardDisableHandler extends Handler { if (dpm != null) { try { mAllowDisableKeyguard = dpm.getPasswordQuality(null, - ActivityManagerNative.getDefault().getCurrentUser().id) + ActivityManager.getService().getCurrentUser().id) == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ? ALLOW_DISABLE_YES : ALLOW_DISABLE_NO; } catch (RemoteException re) { diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index 1ccf7229cc87..01a50b7ef340 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -26,6 +26,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.animation.ValueAnimator; import android.content.res.Resources; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -43,6 +44,7 @@ import android.view.IPinnedStackListener; import com.android.internal.os.BackgroundThread; import com.android.internal.policy.PipMotionHelper; import com.android.internal.policy.PipSnapAlgorithm; +import com.android.server.UiThread; import java.io.PrintWriter; @@ -55,7 +57,7 @@ class PinnedStackController { private final WindowManagerService mService; private final DisplayContent mDisplayContent; - private final Handler mHandler = new Handler(); + private final Handler mHandler = UiThread.getHandler(); private IPinnedStackListener mPinnedStackListener; private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler = @@ -67,6 +69,7 @@ class PinnedStackController { // States that affect how the PIP can be manipulated private boolean mInInteractiveMode; + private boolean mIsMinimized; private boolean mIsImeShowing; private int mImeHeight; private ValueAnimator mBoundsAnimator = null; @@ -101,6 +104,13 @@ class PinnedStackController { } @Override + public void setIsMinimized(final boolean isMinimized) { + mHandler.post(() -> { + mIsMinimized = isMinimized; + }); + } + + @Override public void setSnapToEdge(final boolean snapToEdge) { mHandler.post(() -> { mSnapAlgorithm.setSnapToEdge(snapToEdge); @@ -167,6 +177,25 @@ class PinnedStackController { } /** + * Returns the current bounds (or the default bounds if there are no current bounds) with the + * specified aspect ratio. + */ + Rect getAspectRatioBounds(Rect stackBounds, float aspectRatio) { + // Save the snap fraction, calculate the aspect ratio based on the current bounds + final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds, + getMovementBounds(stackBounds)); + final float radius = PointF.length(stackBounds.width(), stackBounds.height()); + final int height = (int) Math.round(Math.sqrt((radius * radius) / + (aspectRatio * aspectRatio + 1))); + final int width = Math.round(height * aspectRatio); + final int left = (int) (stackBounds.centerX() - width / 2f); + final int top = (int) (stackBounds.centerY() - height / 2f); + stackBounds.set(left, top, left + width, top + height); + mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction); + return stackBounds; + } + + /** * @return the default bounds to show the PIP when there is no active PIP. */ Rect getDefaultBounds() { @@ -227,6 +256,12 @@ class PinnedStackController { false /* adjustForIme */); mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, snapFraction); + if (mIsMinimized) { + final Point displaySize = new Point(mDisplayInfo.logicalWidth, + mDisplayInfo.logicalHeight); + mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds, + displaySize); + } } return postChangeStackBounds; } @@ -256,7 +291,12 @@ class PinnedStackController { final Rect toBounds = new Rect(stackBounds); if (adjustedForIme) { // IME visible - toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top)); + if (stackBounds.top == prevMovementBounds.bottom) { + // If the PIP is resting on top of the IME, then adjust it with the hiding IME + toBounds.offsetTo(toBounds.left, movementBounds.bottom); + } else { + toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top)); + } } else { // IME hidden if (stackBounds.top == prevMovementBounds.bottom) { @@ -314,5 +354,6 @@ class PinnedStackController { pw.println(); pw.println(prefix + " mIsImeShowing=" + mIsImeShowing); pw.println(prefix + " mInInteractiveMode=" + mInInteractiveMode); + pw.println(prefix + " mIsMinimized=" + mIsMinimized); } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f0381352be42..1962ca738892 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -40,9 +40,7 @@ import com.android.server.EventLogTags; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashMap; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_NONE; @@ -55,17 +53,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static com.android.server.wm.AppTransition.TRANSIT_UNSET; + import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; @@ -78,7 +72,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS; import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION; -import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE; @@ -226,29 +219,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return false; } - void getWindows(WindowList output) { - final int count = mChildren.size(); - for (int i = 0; i < count; ++i) { - final DisplayContent dc = mChildren.get(i); - dc.getWindows(output); - } - } - - void getWindows(WindowList output, boolean visibleOnly, boolean appsOnly) { - final int numDisplays = mChildren.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList(); - for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { - final WindowState w = windowList.get(winNdx); - if ((!visibleOnly || w.mWinAnimator.getShown()) - && (!appsOnly || w.mAppToken != null)) { - output.add(w); - } - } - } - } - - void getWindowsByName(WindowList output, String name) { + void getWindowsByName(ArrayList<WindowState> output, String name) { int objectId = 0; // See if this is an object ID. try { @@ -256,36 +227,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { name = null; } catch (RuntimeException e) { } - final int numDisplays = mChildren.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList(); - for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { - final WindowState w = windowList.get(winNdx); - if (name != null) { - if (w.mAttrs.getTitle().toString().contains(name)) { - output.add(w); - } - } else if (System.identityHashCode(w) == objectId) { - output.add(w); - } - } - } + + getWindowsByName(output, name, objectId); } - WindowState findWindow(int hashCode) { - final int numDisplays = mChildren.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ReadOnlyWindowList windows = mChildren.get(displayNdx).getReadOnlyWindowList(); - final int numWindows = windows.size(); - for (int winNdx = 0; winNdx < numWindows; ++winNdx) { - final WindowState w = windows.get(winNdx); - if (System.identityHashCode(w) == hashCode) { - return w; + private void getWindowsByName(ArrayList<WindowState> output, String name, int objectId) { + forAllWindows((w) -> { + if (name != null) { + if (w.mAttrs.getTitle().toString().contains(name)) { + output.add(w); } + } else if (System.identityHashCode(w) == objectId) { + output.add(w); } - } - - return null; + }, true /* traverseTopToBottom */); } /** @@ -321,15 +276,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return null; } - // TODO: Users would have their own window containers under the display container? - void switchUser() { - final int count = mChildren.size(); - for (int i = 0; i < count; ++i) { - final DisplayContent dc = mChildren.get(i); - dc.switchUser(); - } - } - /** * Set new display override config and return array of ids of stacks that were changed during * update. If called for the default display, global configuration will also be updated. @@ -406,81 +352,50 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { } void setSecureSurfaceState(int userId, boolean disabled) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList(); - for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { - final WindowState win = windows.get(winNdx); - if (win.mHasSurface && userId == UserHandle.getUserId(win.mOwnerUid)) { - win.mWinAnimator.setSecureLocked(disabled); - } + forAllWindows((w) -> { + if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) { + w.mWinAnimator.setSecureLocked(disabled); } - } + }, true /* traverseTopToBottom */); } void updateAppOpsState() { - final int count = mChildren.size(); - for (int i = 0; i < count; ++i) { - final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList(); - final int numWindows = windows.size(); - for (int winNdx = 0; winNdx < numWindows; ++winNdx) { - final WindowState win = windows.get(winNdx); - if (win.mAppOp == OP_NONE) { - continue; - } - final int mode = mService.mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(), - win.getOwningPackage()); - win.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT); + forAllWindows((w) -> { + if (w.mAppOp == OP_NONE) { + return; } - } + final int mode = mService.mAppOps.checkOpNoThrow(w.mAppOp, w.getOwningUid(), + w.getOwningPackage()); + w.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT); + }, false /* traverseTopToBottom */); } boolean canShowStrictModeViolation(int pid) { - final int count = mChildren.size(); - for (int i = 0; i < count; ++i) { - final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList(); - final int numWindows = windows.size(); - for (int winNdx = 0; winNdx < numWindows; ++winNdx) { - final WindowState ws = windows.get(winNdx); - if (ws.mSession.mPid == pid && ws.isVisibleLw()) { - return true; - } - } - } - return false; + final WindowState win = getWindow((w) -> w.mSession.mPid == pid && w.isVisibleLw()); + return win != null; } void closeSystemDialogs(String reason) { - final int count = mChildren.size(); - for (int i = 0; i < count; ++i) { - final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList(); - final int numWindows = windows.size(); - for (int j = 0; j < numWindows; ++j) { - final WindowState w = windows.get(j); - if (w.mHasSurface) { - try { - w.mClient.closeSystemDialogs(reason); - } catch (RemoteException e) { - } + forAllWindows((w) -> { + if (w.mHasSurface) { + try { + w.mClient.closeSystemDialogs(reason); + } catch (RemoteException e) { } } - } + }, false /* traverseTopToBottom */); } void removeReplacedWindows() { if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows"); mService.openSurfaceTransaction(); try { - for (int i = mChildren.size() - 1; i >= 0; i--) { - DisplayContent dc = mChildren.get(i); - final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList(); - for (int j = windows.size() - 1; j >= 0; j--) { - final WindowState win = windows.get(j); - final AppWindowToken aToken = win.mAppToken; - if (aToken != null) { - aToken.removeReplacedWindowIfNeeded(win); - } + forAllWindows((w) -> { + final AppWindowToken aToken = w.mAppToken; + if (aToken != null) { + aToken.removeReplacedWindowIfNeeded(w); } - } + }, true /* traverseTopToBottom */); } finally { mService.closeSurfaceTransaction(); if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows"); @@ -505,14 +420,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return hasChanges; } - void updateInputWindows(InputMonitor inputMonitor, WindowState inputFocus, boolean inDrag) { - final int count = mChildren.size(); - for (int i = 0; i < count; ++i) { - final DisplayContent dc = mChildren.get(i); - dc.updateInputWindows(inputMonitor, inputFocus, inDrag); - } - } - boolean reclaimSomeSurfaceMemory(WindowStateAnimator winAnimator, String operation, boolean secure) { final WindowSurfaceController surfaceController = winAnimator.mSurfaceController; @@ -537,19 +444,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { Slog.w(TAG_WM, "No leaked surfaces; killing applications!"); final SparseIntArray pidCandidates = new SparseIntArray(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ReadOnlyWindowList windows = - mChildren.get(displayNdx).getReadOnlyWindowList(); - final int numWindows = windows.size(); - for (int winNdx = 0; winNdx < numWindows; ++winNdx) { - final WindowState ws = windows.get(winNdx); - if (mService.mForceRemoves.contains(ws)) { - continue; + mChildren.get(displayNdx).forAllWindows((w) -> { + if (mService.mForceRemoves.contains(w)) { + return; } - final WindowStateAnimator wsa = ws.mWinAnimator; + final WindowStateAnimator wsa = w.mWinAnimator; if (wsa.mSurfaceController != null) { pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid); } - } + }, false /* traverseTopToBottom */); if (pidCandidates.size() > 0) { int[] pids = new int[pidCandidates.size()]; @@ -760,9 +663,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { WindowToken token = exitingTokens.get(i); if (!token.hasVisible) { exitingTokens.remove(i); - if (token.windowType == TYPE_WALLPAPER) { - displayContent.mWallpaperController.removeWallpaperToken(token); - } } } } @@ -1088,17 +988,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { } void dumpWindowsNoHeader(PrintWriter pw, boolean dumpAll, ArrayList<WindowState> windows) { - final int numDisplays = mChildren.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList(); - for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { - final WindowState w = windowList.get(winNdx); - if (windows == null || windows.contains(w)) { - pw.println(" Window #" + winNdx + " " + w + ":"); - w.dump(pw, " ", dumpAll || windows != null); - } - } - } + final int[] index = new int[1]; + forAllWindows((w) -> { + if (windows == null || windows.contains(w)) { + pw.println(" Window #" + index[0] + " " + w + ":"); + w.dump(pw, " ", dumpAll || windows != null); + index[0] = index[0] + 1; + } + }, true /* traverseTopToBottom */); } void dumpTokens(PrintWriter pw, boolean dumpAll) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index b889db230208..772833c8ff4f 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -589,46 +589,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU } } - void getWindowOnDisplayBeforeToken(DisplayContent dc, WindowToken token, - DisplayContent.GetWindowOnDisplaySearchResult result) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final AppWindowToken current = mChildren.get(i); - if (current == token) { - // We have reach the token we are interested in. End search. - result.reachedToken = true; - return; - } - - // We haven't reached the token yet; if this token is not going to the bottom and - // has windows on this display, then it is a candidate for what we are looking for. - final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current); - if (!current.sendingToBottom && tokenWindowList.size() > 0) { - result.foundWindow = tokenWindowList.get(0); - } - } - } - - void getWindowOnDisplayAfterToken(DisplayContent dc, WindowToken token, - DisplayContent.GetWindowOnDisplaySearchResult result) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final AppWindowToken current = mChildren.get(i); - if (!result.reachedToken) { - if (current == token) { - // We have reached the token we are interested in. Get whichever window occurs - // after it that is on the same display. - result.reachedToken = true; - } - continue; - } - - final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current); - if (tokenWindowList.size() > 0) { - result.foundWindow = tokenWindowList.get(tokenWindowList.size() - 1); - return; - } - } - } - @Override boolean fillsParent() { return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index a0270c605fed..f2c74dffe423 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -132,6 +132,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye // perfectly fit the region it would have been cropped to. We may also avoid certain logic we // would otherwise apply while resizing, while resizing in the bounds animating mode. private boolean mBoundsAnimating = false; + private Rect mBoundsAnimationTarget = new Rect(); // Temporary storage for the new bounds that should be used after the configuration change. // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). @@ -329,6 +330,30 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mDisplayContent.getLogicalDisplayRect(out); } + /** + * Sets the bounds animation target bounds. This can't currently be done in onAnimationStart() + * since that is started on the UiThread. + */ + void setAnimatingBounds(Rect bounds) { + if (bounds != null) { + mBoundsAnimationTarget.set(bounds); + } else { + mBoundsAnimationTarget.setEmpty(); + } + } + + /** + * @return the bounds that the task stack is currently being animated towards, or the current + * stack bounds if there is no animation in progress. + */ + void getAnimatingBounds(Rect outBounds) { + if (!mBoundsAnimationTarget.isEmpty()) { + outBounds.set(mBoundsAnimationTarget); + return; + } + getBounds(outBounds); + } + /** Bounds of the stack with other system factors taken into consideration. */ @Override public void getDimBounds(Rect out) { @@ -834,7 +859,9 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } // TODO: Should each user have there own stacks? + @Override void switchUser() { + super.switchUser(); int top = mChildren.size(); for (int taskNdx = 0; taskNdx < top; ++taskNdx) { Task task = mChildren.get(taskNdx); @@ -1391,6 +1418,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye public void onAnimationEnd() { synchronized (mService.mWindowMap) { mBoundsAnimating = false; + mBoundsAnimationTarget.setEmpty(); mService.requestTraversal(); } if (mStackId == PINNED_STACK_ID) { @@ -1462,30 +1490,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } } - void getWindowOnDisplayBeforeToken(DisplayContent dc, WindowToken token, - DisplayContent.GetWindowOnDisplaySearchResult result) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final Task task = mChildren.get(i); - task.getWindowOnDisplayBeforeToken(dc, token, result); - if (result.reachedToken) { - // We have reach the token we are interested in. End search. - return; - } - } - } - - void getWindowOnDisplayAfterToken(DisplayContent dc, WindowToken token, - DisplayContent.GetWindowOnDisplaySearchResult result) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final Task task = mChildren.get(i); - task.getWindowOnDisplayAfterToken(dc, token, result); - if (result.foundWindow != null) { - // We have found a window after the token. End search. - return; - } - } - } - @Override int getOrientation() { return (StackId.canSpecifyOrientation(mStackId)) 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/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 250d381e614b..7fd8028a9c13 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -17,9 +17,9 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; @@ -30,8 +30,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; -import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; -import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET; import android.os.Bundle; import android.os.Debug; @@ -55,17 +53,14 @@ class WallpaperController { private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM; final private WindowManagerService mService; - private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<>(); + private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>(); // If non-null, this is the currently visible window that is associated // with the wallpaper. private WindowState mWallpaperTarget = null; // If non-null, we are in the middle of animating from one wallpaper target - // to another, and this is the lower one in Z-order. - private WindowState mLowerWallpaperTarget = null; - // If non-null, we are in the middle of animating from one wallpaper target - // to another, and this is the higher one in Z-order. - private WindowState mUpperWallpaperTarget = null; + // to another, and this is the previous wallpaper target. + private WindowState mPrevWallpaperTarget = null; private int mWallpaperAnimLayerAdjustment; @@ -78,7 +73,7 @@ class WallpaperController { // This is set when we are waiting for a wallpaper to tell us it is done // changing its scroll position. - WindowState mWaitingOnWallpaper; + private WindowState mWaitingOnWallpaper; // The last time we had a timeout when waiting for a wallpaper. private long mLastWallpaperTimeoutTime; @@ -110,14 +105,6 @@ class WallpaperController { return mWallpaperTarget; } - WindowState getLowerWallpaperTarget() { - return mLowerWallpaperTarget; - } - - WindowState getUpperWallpaperTarget() { - return mUpperWallpaperTarget; - } - boolean isWallpaperTarget(WindowState win) { return win == mWallpaperTarget; } @@ -135,7 +122,7 @@ class WallpaperController { */ void startWallpaperAnimation(Animation a) { for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { - final WindowToken token = mWallpaperTokens.get(curTokenNdx); + final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); token.startAnimation(a); } } @@ -145,13 +132,11 @@ class WallpaperController { + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) - + " upper=" + mUpperWallpaperTarget - + " lower=" + mLowerWallpaperTarget); + + " prev=" + mPrevWallpaperTarget); return (wallpaperTarget != null && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) - || mUpperWallpaperTarget != null - || mLowerWallpaperTarget != null; + || mPrevWallpaperTarget != null; } boolean isWallpaperTargetAnimating() { @@ -163,7 +148,7 @@ class WallpaperController { final boolean visible = isWallpaperVisible(mWallpaperTarget); for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { - final WindowToken token = mWallpaperTokens.get(curTokenNdx); + final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); token.updateWallpaperVisibility(visible); } } @@ -177,7 +162,7 @@ class WallpaperController { void hideWallpapers(final WindowState winGoingAway) { if (mWallpaperTarget != null - && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) { + && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) { return; } if (mService.mAppTransition.isRunning()) { @@ -189,11 +174,11 @@ class WallpaperController { final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway); for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { - final WindowToken token = mWallpaperTokens.get(i); + final WallpaperWindowToken token = mWallpaperTokens.get(i); token.hideWallpaperToken(wasDeferred, "hideWallpapers"); if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token - + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower=" - + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" + + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); } } @@ -299,12 +284,10 @@ class WallpaperController { Bundle sendWindowWallpaperCommand( WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { - if (window == mWallpaperTarget - || window == mLowerWallpaperTarget - || window == mUpperWallpaperTarget) { + if (window == mWallpaperTarget || window == mPrevWallpaperTarget) { boolean doWait = sync; for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { - final WindowToken token = mWallpaperTokens.get(curTokenNdx); + final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); token.sendWindowWallpaperCommand(action, x, y, z, extras, sync); } @@ -388,51 +371,52 @@ class WallpaperController { return mWallpaperAnimLayerAdjustment; } - private void findWallpaperTarget(ReadOnlyWindowList windows, FindWallpaperTargetResult result) { + private void findWallpaperTarget(DisplayContent dc , FindWallpaperTargetResult result) { final WindowAnimator winAnimator = mService.mAnimator; result.reset(); - WindowState w = null; - int windowDetachedI = -1; - boolean resetTopWallpaper = false; - boolean inFreeformSpace = false; - boolean replacing = false; - boolean keyguardGoingAwayWithWallpaper = false; - boolean needsShowWhenLockedWallpaper = false; + if (mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) { + // In freeform mode we set the wallpaper as its own target, so we don't need an + // additional window to make it visible. + result.setUseTopWallpaperAsTarget(true); + } - for (int i = windows.size() - 1; i >= 0; i--) { - w = windows.get(i); + dc.forAllWindows(w -> { if ((w.mAttrs.type == TYPE_WALLPAPER)) { - if (result.topWallpaper == null || resetTopWallpaper) { - result.setTopWallpaper(w, i); - resetTopWallpaper = false; + if (result.topWallpaper == null || result.resetTopWallpaper) { + result.setTopWallpaper(w); + result.resetTopWallpaper = false; } - continue; + return false; } - resetTopWallpaper = true; + + result.resetTopWallpaper = true; if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { // If this window's app token is hidden and not animating, // it is of no interest to us. if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w); - continue; + return false; } } - if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen=" - + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState); - - if (!inFreeformSpace) { - TaskStack stack = w.getStack(); - inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID; + if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen() + + " mDrawState=" + w.mWinAnimator.mDrawState); + + if (w.mWillReplaceWindow && mWallpaperTarget == null + && !result.useTopWallpaperAsTarget) { + // When we are replacing a window and there was wallpaper before replacement, we + // want to keep the window until the new windows fully appear and can determine the + // visibility, to avoid flickering. + result.setUseTopWallpaperAsTarget(true); } - replacing |= w.mWillReplaceWindow; - keyguardGoingAwayWithWallpaper |= (w.mAppToken != null + final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null && AppTransition.isKeyguardGoingAwayTransit( w.mAppToken.mAppAnimator.getTransit()) && (w.mAppToken.mAppAnimator.getTransitFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0); + boolean needsShowWhenLockedWallpaper = false; if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked() && mService.mPolicy.isKeyguardOccluded()) { @@ -442,248 +426,147 @@ class WallpaperController { || (w.mAppToken != null && !w.mAppToken.fillsParent()); } + if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { + // Keep the wallpaper during Keyguard exit but also when it's needed for a + // non-fullscreen show when locked activity. + result.setUseTopWallpaperAsTarget(true); + } + final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) { - if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w); - result.setWallpaperTarget(w, i); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w); + result.setWallpaperTarget(w); if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) { // The current wallpaper target is animating, so we'll look behind it for // another possible target and figure out what is going on later. if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": token animating, looking behind."); - continue; } - break; + // Found a target! End search. + return true; } else if (w == winAnimator.mWindowDetachedWallpaper) { - windowDetachedI = i; + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, + "Found animating detached wallpaper target win: " + w); + result.setUseTopWallpaperAsTarget(true); } - } - - if (result.wallpaperTarget != null) { - return; - } - - if (windowDetachedI >= 0) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w); - result.setWallpaperTarget(w, windowDetachedI); - } else if (inFreeformSpace || (replacing && mWallpaperTarget != null)) { - // In freeform mode we set the wallpaper as its own target, so we don't need an - // additional window to make it visible. When we are replacing a window and there was - // wallpaper before replacement, we want to keep the window until the new windows fully - // appear and can determine the visibility, to avoid flickering. - result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); + return false; + }, true /* traverseTopToBottom */); - } else if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { - // Keep the wallpaper during Keyguard exit but also when it's needed for a - // non-fullscreen show when locked activity. - result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); + if (result.wallpaperTarget == null && result.useTopWallpaperAsTarget) { + result.setWallpaperTarget(result.topWallpaper); } } private boolean isFullscreen(WindowManager.LayoutParams attrs) { return attrs.x == 0 && attrs.y == 0 - && attrs.width == WindowManager.LayoutParams.MATCH_PARENT - && attrs.height == WindowManager.LayoutParams.MATCH_PARENT; + && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT; } /** Updates the target wallpaper if needed and returns true if an update happened. */ - private boolean updateWallpaperWindowsTarget( - ReadOnlyWindowList windows, FindWallpaperTargetResult result) { + private void updateWallpaperWindowsTarget(DisplayContent dc, + FindWallpaperTargetResult result) { WindowState wallpaperTarget = result.wallpaperTarget; - int wallpaperTargetIndex = result.wallpaperTargetIndex; if (mWallpaperTarget == wallpaperTarget - || (mLowerWallpaperTarget != null && mLowerWallpaperTarget == wallpaperTarget)) { - - if (mLowerWallpaperTarget != null) { - // Is it time to stop animating? - if (!mLowerWallpaperTarget.isAnimatingLw() - || !mUpperWallpaperTarget.isAnimatingLw()) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "No longer animating wallpaper targets!"); - mLowerWallpaperTarget = null; - mUpperWallpaperTarget = null; - mWallpaperTarget = wallpaperTarget; - return true; - } + || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) { + + if (mPrevWallpaperTarget == null) { + return; } - return false; + // Is it time to stop animating? + if (!mPrevWallpaperTarget.isAnimatingLw()) { + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!"); + mPrevWallpaperTarget = null; + mWallpaperTarget = wallpaperTarget; + } + return; } if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget); + "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget); - mLowerWallpaperTarget = null; - mUpperWallpaperTarget = null; + mPrevWallpaperTarget = null; - WindowState oldW = mWallpaperTarget; + final WindowState prevWallpaperTarget = mWallpaperTarget; mWallpaperTarget = wallpaperTarget; - if (wallpaperTarget == null || oldW == null) { - return true; + if (wallpaperTarget == null || prevWallpaperTarget == null) { + return; } // Now what is happening... if the current and new targets are animating, // then we are in our super special mode! - boolean oldAnim = oldW.isAnimatingLw(); + boolean oldAnim = prevWallpaperTarget.isAnimatingLw(); boolean foundAnim = wallpaperTarget.isAnimatingLw(); if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "New animation: " + foundAnim + " old animation: " + oldAnim); if (!foundAnim || !oldAnim) { - return true; + return; } - int oldI = windows.indexOf(oldW); - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "New i: " + wallpaperTargetIndex + " old i: " + oldI); - - if (oldI < 0) { - return true; + if (dc.getWindow(w -> w == prevWallpaperTarget) == null) { + return; } final boolean newTargetHidden = wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.hiddenRequested; - final boolean oldTargetHidden = oldW.mAppToken != null - && oldW.mAppToken.hiddenRequested; - - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "=" - + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "=" - + wallpaperTarget + " hidden=" + newTargetHidden); - - // Set the upper and lower wallpaper targets correctly, - // and make sure that we are positioning the wallpaper below the lower. - if (wallpaperTargetIndex > oldI) { - // The new target is on top of the old one. - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target above old target."); - mUpperWallpaperTarget = wallpaperTarget; - mLowerWallpaperTarget = oldW; - - wallpaperTarget = oldW; - wallpaperTargetIndex = oldI; - } else { - // The new target is below the old one. - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target below old target."); - mUpperWallpaperTarget = oldW; - mLowerWallpaperTarget = wallpaperTarget; - } + final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null + && prevWallpaperTarget.mAppToken.hiddenRequested; + + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: " + + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget + + " hidden=" + newTargetHidden); + + mPrevWallpaperTarget = prevWallpaperTarget; if (newTargetHidden && !oldTargetHidden) { if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target."); // Use the old target if new target is hidden but old target // is not. If they're both hidden, still use the new target. - mWallpaperTarget = oldW; + mWallpaperTarget = prevWallpaperTarget; } else if (newTargetHidden == oldTargetHidden && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken) - && (mService.mOpeningApps.contains(oldW.mAppToken) - || mService.mClosingApps.contains(oldW.mAppToken))) { + && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken) + || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) { // If they're both hidden (or both not hidden), prefer the one that's currently in // opening or closing app list, this allows transition selection logic to better // determine the wallpaper status of opening/closing apps. - mWallpaperTarget = oldW; - } - - result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); - return true; - } - - private boolean updateWallpaperWindowsTargetByLayer(ReadOnlyWindowList windows, - FindWallpaperTargetResult result) { - - WindowState wallpaperTarget = result.wallpaperTarget; - int wallpaperTargetIndex = result.wallpaperTargetIndex; - boolean visible = wallpaperTarget != null; - - if (visible) { - // The window is visible to the compositor...but is it visible to the user? - // That is what the wallpaper cares about. - visible = isWallpaperVisible(wallpaperTarget); - if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); - - // If the wallpaper target is animating, we may need to copy its layer adjustment. - // Only do this if we are not transferring between two wallpaper targets. - mWallpaperAnimLayerAdjustment = - (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null) - ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; - - final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER) - + TYPE_LAYER_OFFSET; - - // Now w is the window we are supposed to be behind... but we - // need to be sure to also be behind any of its attached windows, - // AND any starting window associated with it, AND below the - // maximum layer the policy allows for wallpapers. - while (wallpaperTargetIndex > 0) { - final WindowState wb = windows.get(wallpaperTargetIndex - 1); - final WindowState wbParentWindow = wb.getParentWindow(); - final WindowState wallpaperParentWindow = wallpaperTarget.getParentWindow(); - if (wb.mBaseLayer < maxLayer - && wbParentWindow != wallpaperTarget - && (wallpaperParentWindow == null || wbParentWindow != wallpaperParentWindow) - && (wb.mAttrs.type != TYPE_APPLICATION_STARTING - || wallpaperTarget.mToken == null - || wb.mToken != wallpaperTarget.mToken)) { - // This window is not related to the previous one in any - // interesting way, so stop here. - break; - } - wallpaperTarget = wb; - wallpaperTargetIndex--; - } - } else { - if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target"); + mWallpaperTarget = prevWallpaperTarget; } - result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); - return visible; + result.setWallpaperTarget(wallpaperTarget); } - private boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windows, - WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) { - - // TODO(multidisplay): Wallpapers on main screen only. - final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo(); - final int dw = displayInfo.logicalWidth; - final int dh = displayInfo.logicalHeight; - - // Start stepping backwards from here, ensuring that our wallpaper windows are correctly placed. - boolean changed = false; + private void updateWallpaperTokens(boolean visible) { for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { - final WindowToken token = mWallpaperTokens.get(curTokenNdx); - changed |= token.updateWallpaperWindowsPlacement(windows, wallpaperTarget, - wallpaperTargetIndex, visible, dw, dh, mWallpaperAnimLayerAdjustment); + final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); + token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment); } - - return changed; } - boolean adjustWallpaperWindows(ReadOnlyWindowList windows) { + void adjustWallpaperWindows(DisplayContent dc) { mService.mRoot.mWallpaperMayChange = false; // First find top-most window that has asked to be on top of the wallpaper; // all wallpapers go behind it. - findWallpaperTarget(windows, mFindResults); - final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults); - final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults); - WindowState wallpaperTarget = mFindResults.wallpaperTarget; - int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex; - - if (wallpaperTarget == null && mFindResults.topWallpaper != null) { - // There is no wallpaper target, so it goes at the bottom. - // We will assume it is the same place as last time, if known. - wallpaperTarget = mFindResults.topWallpaper; - wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1; - } else { - // Okay i is the position immediately above the wallpaper. - // Look at what is below it for later. - wallpaperTarget = wallpaperTargetIndex > 0 - ? windows.get(wallpaperTargetIndex - 1) : null; - } + findWallpaperTarget(dc, mFindResults); + updateWallpaperWindowsTarget(dc, mFindResults); + + // The window is visible to the compositor...but is it visible to the user? + // That is what the wallpaper cares about. + final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); if (visible) { + // If the wallpaper target is animating, we may need to copy its layer adjustment. + // Only do this if we are not transferring between two wallpaper targets. + mWallpaperAnimLayerAdjustment = + (mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null) + ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; + if (mWallpaperTarget.mWallpaperX >= 0) { mLastWallpaperX = mWallpaperTarget.mWallpaperX; mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; @@ -700,14 +583,10 @@ class WallpaperController { } } - final boolean changed = updateWallpaperWindowsPlacement( - windows, wallpaperTarget, wallpaperTargetIndex, visible); - - if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" - + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper=" - + mUpperWallpaperTarget); + updateWallpaperTokens(visible); - return changed; + if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget + + " prev=" + mPrevWallpaperTarget); } boolean processWallpaperDrawPendingTimeout() { @@ -725,7 +604,7 @@ class WallpaperController { boolean wallpaperReady = true; for (int curTokenIndex = mWallpaperTokens.size() - 1; curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) { - final WindowToken token = mWallpaperTokens.get(curTokenIndex); + final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex); if (token.hasVisibleNotDrawnWallpaper()) { // We've told this wallpaper to be visible, but it is not drawn yet wallpaperReady = false; @@ -773,23 +652,22 @@ class WallpaperController { } if (adjust) { - dc.adjustWallpaperWindows(); + adjustWallpaperWindows(dc); } } - void addWallpaperToken(WindowToken token) { + void addWallpaperToken(WallpaperWindowToken token) { mWallpaperTokens.add(token); } - void removeWallpaperToken(WindowToken token) { + void removeWallpaperToken(WallpaperWindowToken token) { mWallpaperTokens.remove(token); } void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget); - if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) { - pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); - pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); + if (mPrevWallpaperTarget != null) { + pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget); } pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX); pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); @@ -805,46 +683,30 @@ class WallpaperController { } } - void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) { - if (!mWallpaperTokens.isEmpty()) { - pw.println(); - pw.print(prefix); pw.println("Wallpaper tokens:"); - for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { - WindowToken token = mWallpaperTokens.get(i); - pw.print(prefix); pw.print("Wallpaper #"); pw.print(i); - pw.print(' '); pw.print(token); - if (dumpAll) { - pw.println(':'); - token.dump(pw, " "); - } else { - pw.println(); - } - } - } - } - /** Helper class for storing the results of a wallpaper target find operation. */ final private static class FindWallpaperTargetResult { - int topWallpaperIndex = 0; WindowState topWallpaper = null; - int wallpaperTargetIndex = 0; + boolean useTopWallpaperAsTarget = false; WindowState wallpaperTarget = null; + boolean resetTopWallpaper = false; - void setTopWallpaper(WindowState win, int index) { + void setTopWallpaper(WindowState win) { topWallpaper = win; - topWallpaperIndex = index; } - void setWallpaperTarget(WindowState win, int index) { + void setWallpaperTarget(WindowState win) { wallpaperTarget = win; - wallpaperTargetIndex = index; + } + + void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) { + useTopWallpaperAsTarget = topWallpaperAsTarget; } void reset() { - topWallpaperIndex = 0; topWallpaper = null; - wallpaperTargetIndex = 0; wallpaperTarget = null; + useTopWallpaperAsTarget = false; + resetTopWallpaper = false; } } } diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java new file mode 100644 index 000000000000..8ea1b3b1355a --- /dev/null +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; +import android.view.DisplayInfo; +import android.view.animation.Animation; + +/** + * A token that represents a set of wallpaper windows. + */ +class WallpaperWindowToken extends WindowToken { + + private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM; + + WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit, + DisplayContent dc) { + super(service, token, TYPE_WALLPAPER, explicit, dc); + dc.mWallpaperController.addWallpaperToken(this); + } + + @Override + void setExiting() { + super.setExiting(); + mDisplayContent.mWallpaperController.removeWallpaperToken(this); + } + + void hideWallpaperToken(boolean wasDeferred, String reason) { + for (int j = mChildren.size() - 1; j >= 0; j--) { + final WindowState wallpaper = mChildren.get(j); + wallpaper.hideWallpaperWindow(wasDeferred, reason); + } + hidden = true; + } + + void sendWindowWallpaperCommand( + String action, int x, int y, int z, Bundle extras, boolean sync) { + for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { + final WindowState wallpaper = mChildren.get(wallpaperNdx); + try { + wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync); + // We only want to be synchronous with one wallpaper. + sync = false; + } catch (RemoteException e) { + } + } + } + + void updateWallpaperOffset(int dw, int dh, boolean sync) { + final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; + for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { + final WindowState wallpaper = mChildren.get(wallpaperNdx); + if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) { + final WindowStateAnimator winAnimator = wallpaper.mWinAnimator; + winAnimator.computeShownFrameLocked(); + // No need to lay out the windows - we can just set the wallpaper position directly. + winAnimator.setWallpaperOffset(wallpaper.mShownPosition); + // We only want to be synchronous with one wallpaper. + sync = false; + } + } + } + + void updateWallpaperVisibility(boolean visible) { + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + final int dw = displayInfo.logicalWidth; + final int dh = displayInfo.logicalHeight; + + if (hidden == visible) { + hidden = !visible; + // Need to do a layout to ensure the wallpaper now has the correct size. + mDisplayContent.setLayoutNeeded(); + } + + final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; + for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { + final WindowState wallpaper = mChildren.get(wallpaperNdx); + if (visible) { + wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false); + } + + wallpaper.dispatchWallpaperVisibility(visible); + } + } + + /** + * Starts {@param anim} on all children. + */ + void startAnimation(Animation anim) { + for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) { + final WindowState windowState = mChildren.get(ndx); + windowState.mWinAnimator.setAnimation(anim); + } + } + + void updateWallpaperWindows(boolean visible, int animLayerAdj) { + + if (hidden == visible) { + if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, + "Wallpaper token " + token + " hidden=" + !visible); + hidden = !visible; + // Need to do a layout to ensure the wallpaper now has the correct size. + mDisplayContent.setLayoutNeeded(); + } + + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + final int dw = displayInfo.logicalWidth; + final int dh = displayInfo.logicalHeight; + final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; + for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { + final WindowState wallpaper = mChildren.get(wallpaperNdx); + + if (visible) { + wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false); + } + + // First, make sure the client has the current visibility state. + wallpaper.dispatchWallpaperVisibility(visible); + wallpaper.adjustAnimLayer(animLayerAdj); + + if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " + + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); + } + } + + boolean hasVisibleNotDrawnWallpaper() { + for (int j = mChildren.size() - 1; j >= 0; --j) { + final WindowState wallpaper = mChildren.get(j); + if (wallpaper.hasVisibleNotDrawnWallpaper()) { + return true; + } + } + return false; + } + + @Override + public String toString() { + if (stringName == null) { + StringBuilder sb = new StringBuilder(); + sb.append("WallpaperWindowToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" token="); sb.append(token); sb.append('}'); + stringName = sb.toString(); + } + return stringName; + } +} diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index e30ebcb3a6a1..f5db0b668c22 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -18,10 +18,13 @@ package com.android.server.wm; import android.annotation.CallSuper; import android.content.res.Configuration; -import android.view.animation.Animation; +import com.android.internal.util.ToBooleanFunction; import java.util.Comparator; import java.util.LinkedList; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; @@ -479,19 +482,56 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon return false; } + // TODO: Users would have their own window containers under the display container? + void switchUser() { + for (int i = mChildren.size() - 1; i >= 0; --i) { + mChildren.get(i).switchUser(); + } + } + /** - * Rebuilds the WindowList for the input display content. - * @param addIndex The index in the window list to add the next entry to. - * @return The next index in the window list to. + * For all windows at or below this container call the callback. + * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and + * stops the search if {@link ToBooleanFunction#apply} returns true. + * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of + * z-order, else from bottom-to-top. + * @return True if the search ended before we reached the end of the hierarchy due to + * {@link Function#apply} returning true. */ - // TODO: Hoping we can get rid of WindowList so this method wouldn't be needed. - int rebuildWindowList(int addIndex) { - final int count = mChildren.size(); - for (int i = 0; i < count; i++) { - final WindowContainer wc = mChildren.get(i); - addIndex = wc.rebuildWindowList(addIndex); + boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { + if (traverseTopToBottom) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { + return true; + } + } + } else { + final int count = mChildren.size(); + for (int i = 0; i < count; i++) { + if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { + return true; + } + } } - return addIndex; + return false; + } + + void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { + forAllWindows(w -> { + callback.accept(w); + return false; + }, traverseTopToBottom); + } + + WindowState getWindow(Predicate<WindowState> callback) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + final WindowState w = mChildren.get(i).getWindow(callback); + if (w != null) { + return w; + } + } + + return null; } /** @@ -562,8 +602,7 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon void dumpChildrenNames(StringBuilder out, String prefix) { final String childPrefix = prefix + " "; out.append(getName() + "\n"); - final int count = mChildren.size(); - for (int i = 0; i < count; i++) { + for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer wc = mChildren.get(i); out.append(childPrefix + "#" + i + " "); wc.dumpChildrenNames(out, childPrefix); diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java index d94094ab5c1f..32373f901be3 100644 --- a/services/core/java/com/android/server/wm/WindowLayersController.java +++ b/services/core/java/com/android/server/wm/WindowLayersController.java @@ -23,6 +23,7 @@ import java.util.ArrayDeque; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -60,69 +61,74 @@ class WindowLayersController { private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>(); private WindowState mDockDivider = null; private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>(); - - final void assignWindowLayers(ReadOnlyWindowList windows) { - if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows, + private int mCurBaseLayer; + private int mCurLayer; + private boolean mAnyLayerChanged; + private int mHighestLayerInImeTargetBaseLayer; + private WindowState mImeTarget; + + final void assignWindowLayers(DisplayContent dc) { + if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based", new RuntimeException("here").fillInStackTrace()); - clear(); - int curBaseLayer = 0; - int curLayer = 0; - boolean anyLayerChanged = false; - for (int i = 0, windowCount = windows.size(); i < windowCount; i++) { - final WindowState w = windows.get(i); + reset(); + dc.forAllWindows((w) -> { boolean layerChanged = false; int oldLayer = w.mLayer; - if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) { - curLayer += WINDOW_LAYER_MULTIPLIER; + if (w.mBaseLayer == mCurBaseLayer) { + mCurLayer += WINDOW_LAYER_MULTIPLIER; } else { - curBaseLayer = curLayer = w.mBaseLayer; + mCurBaseLayer = mCurLayer = w.mBaseLayer; } - assignAnimLayer(w, curLayer); + assignAnimLayer(w, mCurLayer); - // TODO: Preserved old behavior of code here but not sure comparing - // oldLayer to mAnimLayer and mLayer makes sense...though the - // worst case would be unintentional layer reassignment. + // TODO: Preserved old behavior of code here but not sure comparing oldLayer to + // mAnimLayer and mLayer makes sense...though the worst case would be unintentional + // layer reassignment. if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) { layerChanged = true; - anyLayerChanged = true; + mAnyLayerChanged = true; } if (w.mAppToken != null) { mHighestApplicationLayer = Math.max(mHighestApplicationLayer, w.mWinAnimator.mAnimLayer); } + if (mImeTarget != null && w.mBaseLayer == mImeTarget.mBaseLayer) { + mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer, + w.mWinAnimator.mAnimLayer); + } + collectSpecialWindows(w); if (layerChanged) { w.scheduleAnimationIfDimming(); } - } + }, false /* traverseTopToBottom */); adjustSpecialWindows(); //TODO (multidisplay): Magnification is supported only for the default display. - if (mService.mAccessibilityController != null && anyLayerChanged - && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) { + if (mService.mAccessibilityController != null && mAnyLayerChanged + && dc.getDisplayId() == DEFAULT_DISPLAY) { mService.mAccessibilityController.onWindowLayersChangedLocked(); } - if (DEBUG_LAYERS) logDebugLayers(windows); + if (DEBUG_LAYERS) logDebugLayers(dc); } - private void logDebugLayers(ReadOnlyWindowList windows) { - for (int i = 0, n = windows.size(); i < n; i++) { - final WindowState w = windows.get(i); + private void logDebugLayers(DisplayContent dc) { + dc.forAllWindows((w) -> { final WindowStateAnimator winAnimator = w.mWinAnimator; Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer + " mLayer=" + w.mLayer + (w.mAppToken == null ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment) + " =mAnimLayer=" + winAnimator.mAnimLayer); - } + }, false /* traverseTopToBottom */); } - private void clear() { + private void reset() { mHighestApplicationLayer = 0; mPinnedWindows.clear(); mInputMethodWindows.clear(); @@ -130,6 +136,13 @@ class WindowLayersController { mOnTopLauncherWindows.clear(); mReplacingWindows.clear(); mDockDivider = null; + + mCurBaseLayer = 0; + mCurLayer = 0; + mAnyLayerChanged = false; + + mImeTarget = mService.mInputMethodTarget; + mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0; } private void collectSpecialWindows(WindowState w) { @@ -172,22 +185,10 @@ class WindowLayersController { layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer); - boolean onTopLauncherVisible = !mOnTopLauncherWindows.isEmpty(); while (!mOnTopLauncherWindows.isEmpty()) { layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer); } - // Make sure IME windows are showing above the dock divider and on-top launcher windows. - if ((mDockDivider != null && mDockDivider.isVisibleLw()) || onTopLauncherVisible) { - while (!mInputMethodWindows.isEmpty()) { - final WindowState w = mInputMethodWindows.remove(); - // Only ever move IME windows up, else we brake IME for windows above the divider. - if (layer > w.mLayer) { - layer = assignAndIncreaseLayerIfNeeded(w, layer); - } - } - } - // We know that we will be animating a relaunching window in the near future, which will // receive a z-order increase. We want the replaced window to immediately receive the same // treatment, e.g. to be above the dock divider. @@ -198,12 +199,26 @@ class WindowLayersController { while (!mPinnedWindows.isEmpty()) { layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer); } + + // Make sure IME is the highest window in the base layer of it's target. + if (mImeTarget != null) { + if (mImeTarget.mAppToken == null) { + // For non-app ime targets adjust the layer we start from to match what we found + // when assigning layers. Otherwise, just use the highest app layer we have some far. + layer = mHighestLayerInImeTargetBaseLayer + WINDOW_LAYER_MULTIPLIER; + } + + while (!mInputMethodWindows.isEmpty()) { + layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer); + } + } + } private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) { if (win != null) { assignAnimLayer(win, layer); - // Make sure we leave space inbetween normal windows for dims and such. + // Make sure we leave space in-between normal windows for dims and such. layer += WINDOW_LAYER_MULTIPLIER; } return layer; 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/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 77237526faf4..507679bedd4c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.Notification; @@ -172,7 +171,6 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.StatusBarManager.DISABLE_MASK; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; @@ -608,17 +606,6 @@ public class WindowManagerService extends IWindowManager.Stub boolean mInputMethodTargetWaitingAnim; WindowState mInputMethodWindow = null; - // TODO: Remove with extreme prejudice! This list is maintained so that we can keep track of - // dialogs that should go on top of the IME so they can be re-arranged in the window list any - // time the IME changes position in the window list. Normally you would have a dialog be a child - // window of the IME, but they don't share the same token since they are added by different - // clients. This doesn't really affect what the user sees on screen since this dialogs have an - // higher base layer than the IME window, but it will affect users of the window list that - // expect the list to represent the order of things on-screen (e.g input service). This makes - // the code for managing the window list hard to follow (see all the places it is used). - // We can remove the use of this field when we automatically assign layers and z-order the - // window list before it is used whenever window container order changes. - final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<>(); boolean mHardKeyboardAvailable; WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; @@ -1019,7 +1006,7 @@ public class WindowManagerService extends IWindowManager.Stub mBoundsAnimationController = new BoundsAnimationController(mAppTransition, UiThread.getHandler()); - mActivityManager = ActivityManagerNative.getDefault(); + mActivityManager = ActivityManager.getService(); mAmInternal = LocalServices.getService(ActivityManagerInternal.class); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); AppOpsManager.OnOpChangedInternalListener opListener = @@ -1379,19 +1366,16 @@ public class WindowManagerService extends IWindowManager.Stub boolean imMayMove = true; + win.mToken.addWindow(win); if (type == TYPE_INPUT_METHOD) { win.mGivenInsetsPending = true; mInputMethodWindow = win; - win.mToken.addImeWindow(win); + displayContent.computeImeTarget(true /* updateImeTarget */); imMayMove = false; } else if (type == TYPE_INPUT_METHOD_DIALOG) { - mInputMethodDialogs.add(win); - win.mToken.addWindow(win); - displayContent.moveInputMethodDialogs( - displayContent.findDesiredInputMethodWindowIndex(true)); + displayContent.computeImeTarget(true /* updateImeTarget */); imMayMove = false; } else { - win.mToken.addWindow(win); if (type == TYPE_WALLPAPER) { displayContent.mWallpaperController.clearLastWallpaperTimeoutTime(); displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; @@ -1464,7 +1448,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (imMayMove) { - displayContent.moveInputMethodWindowsIfNeeded(false); + displayContent.computeImeTarget(true /* updateImeTarget */); } // Don't do layout here, the window must call @@ -1648,8 +1632,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mInputMethodWindow == win) { mInputMethodWindow = null; - } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { - mInputMethodDialogs.remove(win); } final WindowToken token = win.mToken; @@ -1679,13 +1661,11 @@ public class WindowManagerService extends IWindowManager.Stub dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } - if (dc != null && dc.removeFromWindowList(win)) { - if (!mWindowPlacerLocked.isInLayout()) { - dc.assignWindowLayers(true /* setLayoutNeeded */); - mWindowPlacerLocked.performSurfacePlacement(); - if (win.mAppToken != null) { - win.mAppToken.updateReportedVisibilityLocked(); - } + if (dc != null && !mWindowPlacerLocked.isInLayout()) { + dc.assignWindowLayers(true /* setLayoutNeeded */); + mWindowPlacerLocked.performSurfacePlacement(); + if (win.mAppToken != null) { + win.mAppToken.updateReportedVisibilityLocked(); } } @@ -1932,6 +1912,12 @@ public class WindowManagerService extends IWindowManager.Stub || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) { win.mAppToken.checkKeyguardFlagsChanged(); } + if (((attrChanges & LayoutParams.ACCESSIBILITY_TITLE_CHANGED) != 0) + && (mAccessibilityController != null) + && (win.getDisplayId() == DEFAULT_DISPLAY)) { + // No move or resize, but the controller checks for title changes as well + mAccessibilityController.onSomeWindowResizedOrMovedLocked(); + } } if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility @@ -2060,14 +2046,15 @@ public class WindowManagerService extends IWindowManager.Stub // reassign them at this point if the IM window state gets shuffled boolean toBeDisplayed = (result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0; final DisplayContent dc = win.getDisplayContent(); - if (imMayMove && (dc.moveInputMethodWindowsIfNeeded(false) || toBeDisplayed)) { - // Little hack here -- we -should- be able to rely on the function to return true if - // the IME has moved and needs its layer recomputed. However, if the IME was hidden - // and isn't actually moved in the list, its layer may be out of data so we make - // sure to recompute it. - // TODO: Probably not needed once the window list always has the right z-ordering - // when the window hierarchy is updated. - dc.assignWindowLayers(false /* setLayoutNeeded */); + if (imMayMove) { + dc.computeImeTarget(true /* updateImeTarget */); + if (toBeDisplayed) { + // Little hack here -- we -should- be able to rely on the function to return + // true if the IME has moved and needs its layer recomputed. However, if the IME + // was hidden and isn't actually moved in the list, its layer may be out of data + // so we make sure to recompute it. + dc.assignWindowLayers(false /* setLayoutNeeded */); + } } if (wallpaperMayMove) { @@ -2409,9 +2396,10 @@ public class WindowManagerService extends IWindowManager.Stub + " displayId=" + displayId); return; } - token = new WindowToken(this, binder, type, true, dc); if (type == TYPE_WALLPAPER) { - dc.mWallpaperController.addWallpaperToken(token); + new WallpaperWindowToken(this, binder, true, dc); + } else { + new WindowToken(this, binder, type, true, dc); } } } @@ -2440,9 +2428,6 @@ public class WindowManagerService extends IWindowManager.Stub } token.setExiting(); - if (token.windowType == TYPE_WALLPAPER) { - dc.mWallpaperController.removeWallpaperToken(token); - } mInputMonitor.updateInputWindowsLw(true /*force*/); } @@ -3349,7 +3334,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mAppTransition.isTransitionSet()) { task.setSendingToBottom(false); } - displayContent.rebuildAppWindowsAndLayoutIfNeeded(); + displayContent.layoutAndAssignWindowLayersIfNeeded(); } } finally { Binder.restoreCallingIdentity(origId); @@ -3371,7 +3356,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mAppTransition.isTransitionSet()) { task.setSendingToBottom(true); } - stack.getDisplayContent().rebuildAppWindowsAndLayoutIfNeeded(); + stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } } finally { Binder.restoreCallingIdentity(origId); @@ -3398,7 +3383,7 @@ public class WindowManagerService extends IWindowManager.Stub public Rect getPictureInPictureDefaultBounds(int displayId) { synchronized (mWindowMap) { if (!mSupportsPictureInPicture) { - return new Rect(); + return null; } final DisplayContent displayContent = mRoot.getDisplayContent(displayId); @@ -3410,7 +3395,7 @@ public class WindowManagerService extends IWindowManager.Stub public Rect getPictureInPictureMovementBounds(int displayId) { synchronized (mWindowMap) { if (!mSupportsPictureInPicture) { - return new Rect(); + return null; } final Rect stackBounds = new Rect(); @@ -3424,6 +3409,47 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void setPictureInPictureAspectRatio(float aspectRatio) { + synchronized (mWindowMap) { + if (!mSupportsPictureInPicture) { + return; + } + + final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID); + if (stack == null) { + return; + } + + animateResizePinnedStack(getPictureInPictureBounds( + stack.getDisplayContent().getDisplayId(), aspectRatio), -1); + } + } + + public Rect getPictureInPictureBounds(int displayId, float aspectRatio) { + synchronized (mWindowMap) { + if (!mSupportsPictureInPicture) { + return null; + } + + final Rect stackBounds; + final DisplayContent displayContent; + final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID); + if (stack != null) { + // If the stack exists, then use its final bounds to calculate the new aspect ratio + // bounds. + displayContent = stack.getDisplayContent(); + stackBounds = new Rect(); + stack.getAnimatingBounds(stackBounds); + } else { + // Otherwise, just calculate the aspect ratio bounds from the default bounds + displayContent = mRoot.getDisplayContent(displayId); + stackBounds = displayContent.getPinnedStackController().getDefaultBounds(); + } + return displayContent.getPinnedStackController().getAspectRatioBounds(stackBounds, + aspectRatio); + } + } + /** * Place a TaskStack on a DisplayContent. Will create a new TaskStack if none is found with * specified stackId. @@ -3572,6 +3598,11 @@ public class WindowManagerService extends IWindowManager.Stub notifyKeyguardFlagsChanged(null /* callback */); } + @Override + public void notifyKeyguardTrustedChanged() { + mH.sendEmptyMessage(H.NOTIFY_KEYGUARD_TRUSTED_CHANGED); + } + /** * Re-sizes a stack and its containing tasks. * @param stackId Id of stack to resize. @@ -4571,7 +4602,7 @@ public class WindowManagerService extends IWindowManager.Stub return null; } } - return displayContent.screenshotApplications(appToken, displayId, width, height, + return displayContent.screenshotApplications(appToken, width, height, includeFullDisplay, frameScale, config, wallpaperOnly); } @@ -4738,37 +4769,42 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - final DisplayContent displayContent = mRoot.getDisplayContent(displayId); - final ReadOnlyWindowList windows = displayContent.getReadOnlyWindowList(); + final DisplayContent dc = mRoot.getDisplayContent(displayId); final int oldRotation = mRotation; int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation); - boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation); + final boolean rotateSeamlessly; - if (rotateSeamlessly) { - for (int i = windows.size() - 1; i >= 0; i--) { - WindowState w = windows.get(i); + if (mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) { + final WindowState seamlessRotated = dc.getWindow((w) -> w.mSeamlesslyRotated); + if (seamlessRotated != null) { // We can't rotate (seamlessly or not) while waiting for the last seamless rotation // to complete (that is, waiting for windows to redraw). It's tempting to check - // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal. - if (w.mSeamlesslyRotated) { - return false; - } - // In what can only be called an unfortunate workaround we require - // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE - // flag. Due to limitations in the client API, there is no way for - // the client to set this flag in a race free fashion. If we seamlessly rotate - // a window which does not have this flag, but then gains it, we will get - // an incorrect visual result (rotated viewfinder). This means if we want to - // support seamlessly rotating windows which could gain this flag, we can't - // rotate windows without it. This limits seamless rotation in N to camera framework - // users, windows without children, and native code. This is unfortunate but - // having the camera work is our primary goal. - if (w.isChildWindow() & w.isVisibleNow() && - !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) { - rotateSeamlessly = false; - } + // w.mSeamlessRotationCount but that could be incorrect in the case of + // window-removal. + return false; } + + final WindowState cantSeamlesslyRotate = dc.getWindow((w) -> + w.isChildWindow() && w.isVisibleNow() + && !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()); + if (cantSeamlesslyRotate != null) { + // In what can only be called an unfortunate workaround we require seamlessly + // rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE flag. Due to + // limitations in the client API, there is no way for the client to set this flag in + // a race free fashion. If we seamlessly rotate a window which does not have this + // flag, but then gains it, we will get an incorrect visual result + // (rotated viewfinder). This means if we want to support seamlessly rotating + // windows which could gain this flag, we can't rotate windows without it. This + // limits seamless rotation in N to camera framework users, windows without + // children, and native code. This is unfortunate but having the camera work is our + // primary goal. + rotateSeamlessly = false; + } else { + rotateSeamlessly = true; + } + } else { + rotateSeamlessly = false; } // TODO: Implement forced rotation changes. @@ -4800,9 +4836,9 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION); mWaitingForConfig = true; - displayContent.setLayoutNeeded(); + dc.setLayoutNeeded(); final int[] anim = new int[2]; - if (displayContent.isDimming()) { + if (dc.isDimming()) { anim[0] = anim[1] = 0; } else { mPolicy.selectRotationAnimationLw(anim); @@ -4811,8 +4847,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!rotateSeamlessly) { startFreezingDisplayLocked(inTransaction, anim[0], anim[1]); // startFreezingDisplayLocked can reset the ScreenRotationAnimation. - screenRotationAnimation = - mAnimator.getScreenRotationAnimationLocked(displayId); + screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(displayId); } else { // The screen rotation animation uses a screenshot to freeze the screen // while windows resize underneath. @@ -4830,9 +4865,9 @@ public class WindowManagerService extends IWindowManager.Stub // the top of the method, the caller is obligated to call computeNewConfigurationLocked(). // By updating the Display info here it will be available to // computeScreenConfigurationLocked later. - updateDisplayAndOrientationLocked(displayContent.getConfiguration().uiMode, displayId); + updateDisplayAndOrientationLocked(dc.getConfiguration().uiMode, displayId); - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + final DisplayInfo displayInfo = dc.getDisplayInfo(); if (!inTransaction) { if (SHOW_TRANSACTIONS) { Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked"); @@ -4853,10 +4888,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (rotateSeamlessly) { - for (int i = windows.size() - 1; i >= 0; i--) { - WindowState w = windows.get(i); - w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation); - } + dc.forAllWindows(w -> { + w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation); + }, true /* traverseTopToBottom */); } mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); @@ -4869,8 +4903,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - for (int i = windows.size() - 1; i >= 0; i--) { - WindowState w = windows.get(i); + dc.forAllWindows(w -> { // Discard surface after orientation change, these can't be reused. if (w.mAppToken != null) { w.mAppToken.destroySavedSurfaces(); @@ -4881,7 +4914,8 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.mOrientationChangeComplete = false; w.mLastFreezeDuration = 0; } - } + + }, true /* traverseTopToBottom */); if (rotateSeamlessly) { mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT); @@ -4899,7 +4933,7 @@ public class WindowManagerService extends IWindowManager.Stub // Announce rotation only if we will not animate as we already have the // windows in final state. Otherwise, we make this call at the rotation end. if (screenRotationAnimation == null && mAccessibilityController != null - && displayContent.getDisplayId() == DEFAULT_DISPLAY) { + && dc.getDisplayId() == DEFAULT_DISPLAY) { mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation); } @@ -5130,9 +5164,11 @@ public class WindowManagerService extends IWindowManager.Stub boolean result = true; - final WindowList windows = new WindowList(); + final ArrayList<WindowState> windows = new ArrayList(); synchronized (mWindowMap) { - mRoot.getWindows(windows); + mRoot.forAllWindows(w -> { + windows.add(w); + }, false /* traverseTopToBottom */); } BufferedWriter out = null; @@ -5359,7 +5395,7 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized (mWindowMap) { - return mRoot.findWindow(hashCode); + return mRoot.getWindow((w) -> System.identityHashCode(w) == hashCode); } } @@ -5405,17 +5441,16 @@ public class WindowManagerService extends IWindowManager.Stub return config; } - private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int uiMode, - int dw, int dh) { - // TODO: Multidisplay: for now only use with default display. - final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode); + private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation, + int uiMode, int dw, int dh) { + final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode, displayId); if (width < displayInfo.smallestNominalAppWidth) { displayInfo.smallestNominalAppWidth = width; } if (width > displayInfo.largestNominalAppWidth) { displayInfo.largestNominalAppWidth = width; } - final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode); + final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode, displayId); if (height < displayInfo.smallestNominalAppHeight) { displayInfo.smallestNominalAppHeight = height; } @@ -5425,11 +5460,10 @@ public class WindowManagerService extends IWindowManager.Stub } private int reduceConfigLayout(int curLayout, int rotation, float density, - int dw, int dh, int uiMode) { - // TODO: Multidisplay: for now only use with default display. + int dw, int dh, int uiMode, int displayId) { // Get the app screen size at this rotation. - int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode); - int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode); + int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId); + int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId); // Compute the screen layout size class for this rotation. int longSize = w; @@ -5444,9 +5478,8 @@ public class WindowManagerService extends IWindowManager.Stub return Configuration.reduceScreenLayout(curLayout, longSize, shortSize); } - private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated, - int uiMode, int dw, int dh, float density, Configuration outConfig) { - // TODO: Multidisplay: for now only use with default display. + private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId, + boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) { // We need to determine the smallest width that will occur under normal // operation. To this, start with the base screen size and compute the @@ -5464,24 +5497,33 @@ public class WindowManagerService extends IWindowManager.Stub displayInfo.smallestNominalAppHeight = 1<<30; displayInfo.largestNominalAppWidth = 0; displayInfo.largestNominalAppHeight = 0; - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw); + adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw, + unrotDh); + adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh, + unrotDw); + adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw, + unrotDh); + adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh, + unrotDw); int sl = Configuration.resetScreenLayout(outConfig.screenLayout); - sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode); - sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode); - sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode); - sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode); + sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode, + displayId); + sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode, + displayId); + sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode, + displayId); + sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode, + displayId); outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density); outConfig.screenLayout = sl; } private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode, - DisplayMetrics dm, int dw, int dh) { - // TODO: Multidisplay: for now only use with default display. - dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode); - dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode); + DisplayMetrics dm, int dw, int dh, int displayId) { + dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, + displayId); + dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, + displayId); float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f); if (curSize == 0 || size < curSize) { @@ -5490,8 +5532,8 @@ public class WindowManagerService extends IWindowManager.Stub return curSize; } - private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw, int dh) { - // TODO: Multidisplay: for now only use with default display. + private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw, + int dh, int displayId) { mTmpDisplayMetrics.setTo(dm); final DisplayMetrics tmpDm = mTmpDisplayMetrics; final int unrotDw, unrotDh; @@ -5502,10 +5544,14 @@ public class WindowManagerService extends IWindowManager.Stub unrotDw = dw; unrotDh = dh; } - int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw); + int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh, + displayId); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw, + displayId); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh, + displayId); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw, + displayId); return sw; } @@ -5540,8 +5586,9 @@ public class WindowManagerService extends IWindowManager.Stub } // Update application display metrics. - final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode); - final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode); + final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode, displayId); + final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode, + displayId); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); displayInfo.rotation = mRotation; displayInfo.logicalWidth = dw; @@ -5580,15 +5627,15 @@ public class WindowManagerService extends IWindowManager.Stub config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; config.screenWidthDp = - (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode) / + (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode, displayId) / mDisplayMetrics.density); config.screenHeightDp = - (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode) / + (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode, displayId) / mDisplayMetrics.density); final boolean rotated = (mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270); - computeSizeRangesAndScreenLayout(displayInfo, rotated, config.uiMode, dw, dh, + computeSizeRangesAndScreenLayout(displayInfo, displayId, rotated, config.uiMode, dw, dh, mDisplayMetrics.density, config); config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK) @@ -5599,7 +5646,7 @@ public class WindowManagerService extends IWindowManager.Stub config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, - mDisplayMetrics, dw, dh); + mDisplayMetrics, dw, dh, displayId); config.densityDpi = displayInfo.logicalDensityDpi; // Update the configuration based on available input devices, lid switch, @@ -6110,6 +6157,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int SEAMLESS_ROTATION_TIMEOUT = 54; public static final int RESTORE_POINTER_ICON = 55; public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56; + public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57; /** * Used to denote that an integer field in a message will not be used. @@ -6748,6 +6796,11 @@ public class WindowManagerService extends IWindowManager.Stub case NOTIFY_KEYGUARD_FLAGS_CHANGED: { mAmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj); } + break; + case NOTIFY_KEYGUARD_TRUSTED_CHANGED: { + mAmInternal.notifyKeyguardTrustedChanged(); + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); @@ -7242,7 +7295,7 @@ public class WindowManagerService extends IWindowManager.Stub changes |= FINISH_LAYOUT_REDO_LAYOUT; if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG_WM, "Wallpaper layer changed: assigning layers + relayout"); - dc.moveInputMethodWindowsIfNeeded(true); + dc.computeImeTarget(true /* updateImeTarget */); mRoot.mWallpaperMayChange = true; // Since the window list has been rebuilt, focus might have to be recomputed since the // actual order of windows might have changed again. @@ -7335,10 +7388,25 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); // TODO(multidisplay): Focused windows on default display only. final DisplayContent displayContent = getDefaultDisplayContentLocked(); - final boolean imWindowChanged = displayContent.moveInputMethodWindowsIfNeeded( - mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS - && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES); + boolean imWindowChanged = false; + if (mInputMethodWindow != null) { + final WindowState prevTarget = mInputMethodTarget; + final WindowState newTarget = + displayContent.computeImeTarget(true /* updateImeTarget*/); + + imWindowChanged = prevTarget != newTarget; + + if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS + && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) { + final int prevImeAnimLayer = mInputMethodWindow.mWinAnimator.mAnimLayer; + displayContent.assignWindowLayers(false /* setLayoutNeeded */); + imWindowChanged |= + prevImeAnimLayer != mInputMethodWindow.mWinAnimator.mAnimLayer; + } + } + if (imWindowChanged) { + mWindowsChanged = true; displayContent.setLayoutNeeded(); newFocus = mRoot.computeFocusedWindow(); } @@ -7813,7 +7881,6 @@ public class WindowManagerService extends IWindowManager.Stub private void dumpTokensLocked(PrintWriter pw, boolean dumpAll) { pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)"); mRoot.dumpTokens(pw, dumpAll); - mRoot.mWallpaperController.dumpTokens(pw, " ", dumpAll); if (!mFinishedStarting.isEmpty()) { pw.println(); pw.println(" Finishing start of application tokens:"); @@ -7859,16 +7926,6 @@ public class WindowManagerService extends IWindowManager.Stub ArrayList<WindowState> windows) { mRoot.dumpWindowsNoHeader(pw, dumpAll, windows); - if (mInputMethodDialogs.size() > 0) { - pw.println(); - pw.println(" Input method dialogs:"); - for (int i=mInputMethodDialogs.size()-1; i>=0; i--) { - WindowState w = mInputMethodDialogs.get(i); - if (windows == null || windows.contains(w)) { - pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w); - } - } - } if (mPendingRemove.size() > 0) { pw.println(); pw.println(" Remove pending for:"); @@ -8027,7 +8084,7 @@ public class WindowManagerService extends IWindowManager.Stub private boolean dumpWindows(PrintWriter pw, String name, String[] args, int opti, boolean dumpAll) { - final WindowList windows = new WindowList(); + final ArrayList<WindowState> windows = new ArrayList(); if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) { final boolean appsOnly = name.contains("apps"); final boolean visibleOnly = name.contains("visible"); @@ -8036,7 +8093,12 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.dumpDisplayContents(pw); } - mRoot.getWindows(windows, visibleOnly, appsOnly); + mRoot.forAllWindows((w) -> { + if ((!visibleOnly || w.mWinAnimator.getShown()) + && (!appsOnly || w.mAppToken != null)) { + windows.add(w); + } + }, true /* traverseTopToBottom */); } } else { synchronized(mWindowMap) { @@ -8197,6 +8259,8 @@ public class WindowManagerService extends IWindowManager.Stub StringBuilder output = new StringBuilder(); mRoot.dumpChildrenNames(output, " "); pw.println(output.toString()); + pw.println(" "); + mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */); } return; } else { @@ -8450,6 +8514,7 @@ public class WindowManagerService extends IWindowManager.Stub } final Rect originalBounds = new Rect(); stack.getBounds(originalBounds); + stack.setAnimatingBounds(bounds); UiThread.getHandler().post(new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 972c35911b39..d959d8c715ca 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -53,12 +53,16 @@ import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManagerPolicy; +import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputWindowHandle; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; @@ -72,6 +76,7 @@ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_ import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; @@ -111,6 +116,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIO import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; @@ -136,55 +142,6 @@ import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; -class WindowList extends ArrayList<WindowState> { - - /** - * Read-only interface for the window list that the creator of the window list can pass-out to - * other users to prevent them from modifying the window list. - */ - private ReadOnlyWindowList mReadOnly; - - WindowList() { - mReadOnly = new ReadOnlyWindowList(this); - } - - /** Returns the read-only interface for this window list. */ - ReadOnlyWindowList getReadOnly() { - return mReadOnly; - } -} - -/** - * Read-only interface for a list of windows. It is common for the owner of a list of windows to - * want to provide a way for external classes to iterate of its windows, but prevent them from - * modifying the list in any way. This call provides a way for them to do that by wrapping the - * original window list and only exposing the read-only APIs. - */ -final class ReadOnlyWindowList { - // List of windows this read-only class is tied to. - private final WindowList mWindows; - - ReadOnlyWindowList(WindowList windows) { - mWindows = windows; - } - - WindowState get(int index) { - return mWindows.get(index); - } - - int indexOf(WindowState w) { - return mWindows.indexOf(w); - } - - int size() { - return mWindows.size(); - } - - boolean isEmpty() { - return mWindows.isEmpty(); - } -} - /** A window in the window manager. */ class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState { static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM; @@ -488,13 +445,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * or some other higher level component said so (e.g. activity manager). * TODO: We should either have different booleans for the removal reason or use a bit-field. */ - private boolean mWindowRemovalAllowed; - - /** - * Temp for keeping track of windows that have been removed when - * rebuilding window list. - */ - boolean mRebuilding; + boolean mWindowRemovalAllowed; // Input channel and input window handle used by the input dispatcher. final InputWindowHandle mInputWindowHandle; @@ -1399,7 +1350,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * being visible. */ boolean isOnScreen() { - if (!mHasSurface || mDestroying) { + if (!mHasSurface || mDestroying || !mPolicyVisibility) { return false; } final AppWindowToken atoken = mAppToken; @@ -1763,7 +1714,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final DisplayContent dc = getDisplayContent(); if (mService.mInputMethodTarget == this) { - dc.moveInputMethodWindowsIfNeeded(false); + dc.computeImeTarget(true /* updateImeTarget */); } final int type = mAttrs.type; @@ -1947,9 +1898,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } int getAnimLayerAdjustment() { - final boolean isImeType = - mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG; - if (isImeType && mService.mInputMethodTarget != null) { + if (mIsImWindow && mService.mInputMethodTarget != null) { final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken; if (appToken != null) { return appToken.mAppAnimator.animLayerAdjustment; @@ -1975,6 +1924,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mLayer + specialAdjustment; } + boolean canBeImeTarget() { + final int fl = mAttrs.flags & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); + final int type = mAttrs.type; + + if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM) + && type != TYPE_APPLICATION_STARTING) { + return false; + } + + if (DEBUG_INPUT_METHOD) { + Slog.i(TAG_WM, "isVisibleOrAdding " + this + ": " + isVisibleOrAdding()); + if (!isVisibleOrAdding()) { + Slog.i(TAG_WM, " mSurfaceController=" + mWinAnimator.mSurfaceController + + " relayoutCalled=" + mRelayoutCalled + + " viewVis=" + mViewVisibility + + " policyVis=" + mPolicyVisibility + + " policyVisAfterAnim=" + mPolicyVisibilityAfterAnim + + " parentHidden=" + isParentWindowHidden() + + " exiting=" + mAnimatingExit + " destroying=" + mDestroying); + if (mAppToken != null) { + Slog.i(TAG_WM, " mAppToken.hiddenRequested=" + mAppToken.hiddenRequested); + } + } + } + return isVisibleOrAdding(); + } + void scheduleAnimationIfDimming() { final DisplayContent dc = getDisplayContent(); if (dc == null) { @@ -2129,7 +2105,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } - void removeReplacedWindow() { + private void removeReplacedWindow() { if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + this); if (isDimming()) { transferDimToReplacement(); @@ -2182,6 +2158,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + @Override + void switchUser() { + super.switchUser(); + if (isHiddenFromUserLocked()) { + if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + this + + ", attrs=" + mAttrs.type + ", belonging to " + mOwnerUid); + hideLw(false); + } + } + int getTouchableRegion(Region region, int flags) { final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; if (modal && mAppToken != null) { @@ -3543,16 +3529,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mIsChildWindow; } - /** - * Returns the bottom child window in regards to z-order of this window or null if no children. - */ - WindowState getBottomChild() { - // Child windows are z-ordered based on sub-layer using {@link #sWindowSubLayerComparator} - // and the child with the lowest z-order will be at the head of the list. - WindowState c = mChildren.peekFirst(); - return c == null ? null : c; - } - boolean layoutInParentFrame() { return mIsChildWindow && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0; @@ -3839,41 +3815,97 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - int rebuildWindowList(int addIndex) { - return reAddWindow(addIndex); + boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { + if (mChildren.isEmpty()) { + // The window has no children so we just return it. + return callback.apply(this); + } + + if (traverseTopToBottom) { + return forAllWindowTopToBottom(callback); + } else { + return forAllWindowBottomToTop(callback); + } } - // TODO: come-up with a better name for this method that represents what it does. - // Or, it is probably not going to matter anyways if we are successful in getting rid of - // the WindowList concept. - int reAddWindow(int index) { - final DisplayContent dc = getDisplayContent(); - // Adding child windows relies on child windows being ordered by mSubLayer using - // {@link #sWindowSubLayerComparator}. - final int childCount = mChildren.size(); - boolean winAdded = false; - for (int j = 0; j < childCount; j++) { - final WindowState child = mChildren.get(j); - if (!winAdded && child.mSubLayer >= 0) { - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, - "Re-adding child window at " + index + ": " + child); - mRebuilding = false; - dc.addToWindowList(this, index); - index++; - winAdded = true; + private boolean forAllWindowBottomToTop(ToBooleanFunction<WindowState> callback) { + // We want to consumer the negative sublayer children first because they need to appear + // below the parent, then this window (the parent), and then the positive sublayer children + // because they need to appear above the parent. + int i = 0; + final int count = mChildren.size(); + WindowState child = mChildren.get(i); + + while (i < count && child.mSubLayer < 0) { + if (callback.apply(child)) { + return true; + } + i++; + if (i >= count) { + break; } - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Re-adding window at " + index + ": " + child); - child.mRebuilding = false; - dc.addToWindowList(child, index); - index++; - } - if (!winAdded) { - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Re-adding window at " + index + ": " + this); - mRebuilding = false; - dc.addToWindowList(this, index); - index++; - } - return index; + child = mChildren.get(i); + } + + if (callback.apply(this)) { + return true; + } + + while (i < count) { + if (callback.apply(child)) { + return true; + } + i++; + if (i >= count) { + break; + } + child = mChildren.get(i); + } + + return false; + } + + private boolean forAllWindowTopToBottom(ToBooleanFunction<WindowState> callback) { + // We want to consumer the positive sublayer children first because they need to appear + // above the parent, then this window (the parent), and then the negative sublayer children + // because they need to appear above the parent. + int i = mChildren.size() - 1; + WindowState child = mChildren.get(i); + + while (i >= 0 && child.mSubLayer >= 0) { + if (callback.apply(child)) { + return true; + } + --i; + if (i < 0) { + break; + } + child = mChildren.get(i); + } + + if (callback.apply(this)) { + return true; + } + + while (i >= 0) { + if (callback.apply(child)) { + return true; + } + --i; + if (i < 0) { + break; + } + child = mChildren.get(i); + } + + return false; + } + + WindowState getWindow(Predicate<WindowState> callback) { + if (callback.test(this)) { + return this; + } + return super.getWindow(callback); } boolean isWindowAnimationSet() { diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index f2682baea614..de808377e880 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -239,7 +239,8 @@ class WindowSurfacePlacer { mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT); final DisplayContent displayContent = mService.getDefaultDisplayContentLocked(); - displayContent.rebuildAppWindowList(); + // TODO: Don't believe this is really needed... + //mService.mWindowsChanged = true; mService.mRoot.mWallpaperMayChange = false; @@ -266,21 +267,9 @@ class WindowSurfacePlacer { mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent, mService.mOpeningApps); - final WindowState lowerWallpaperTarget = - mWallpaperControllerLocked.getLowerWallpaperTarget(); - final WindowState upperWallpaperTarget = - mWallpaperControllerLocked.getUpperWallpaperTarget(); - + final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); boolean openingAppHasWallpaper = false; boolean closingAppHasWallpaper = false; - final AppWindowToken lowerWallpaperAppToken; - final AppWindowToken upperWallpaperAppToken; - if (lowerWallpaperTarget == null) { - lowerWallpaperAppToken = upperWallpaperAppToken = null; - } else { - lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken; - upperWallpaperAppToken = upperWallpaperTarget.mAppToken; - } // Do a first pass through the tokens for two things: // (1) Determine if both the closing and opening app token sets are wallpaper targets, in @@ -294,12 +283,12 @@ class WindowSurfacePlacer { final AppWindowToken wtoken; if (i < closingAppsCount) { wtoken = mService.mClosingApps.valueAt(i); - if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) { + if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { closingAppHasWallpaper = true; } } else { wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount); - if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) { + if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { openingAppHasWallpaper = true; } } @@ -307,14 +296,14 @@ class WindowSurfacePlacer { voiceInteraction |= wtoken.voiceInteraction; if (wtoken.fillsParent()) { - WindowState ws = wtoken.findMainWindow(); + final WindowState ws = wtoken.findMainWindow(); if (ws != null) { animLp = ws.mAttrs; bestAnimLayer = ws.mLayer; fullscreenAnim = true; } } else if (!fullscreenAnim) { - WindowState ws = wtoken.findMainWindow(); + final WindowState ws = wtoken.findMainWindow(); if (ws != null) { if (ws.mLayer > bestAnimLayer) { animLp = ws.mAttrs; @@ -325,7 +314,7 @@ class WindowSurfacePlacer { } transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper, - closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget); + closingAppHasWallpaper); // If all closing windows are obscured, then there is no need to do an animation. This is // the case, for example, when this transition is being done behind the lock screen. @@ -368,12 +357,8 @@ class WindowSurfacePlacer { displayContent.setLayoutNeeded(); // TODO(multidisplay): IMEs are only supported on the default display. - // TODO: Probably not needed once the window list always has the right z-ordering - // when the window hierarchy is updated. final DisplayContent dc = mService.getDefaultDisplayContentLocked(); - if (!dc.moveInputMethodWindowsIfNeeded(true)) { - dc.assignWindowLayers(false /*setLayoutNeeded*/); - } + dc.computeImeTarget(true /* updateImeTarget */); mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/); mService.mFocusMayChange = false; @@ -578,8 +563,7 @@ class WindowSurfacePlacer { } private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper, - boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget, - WindowState upperWallpaperTarget) { + boolean closingAppHasWallpaper) { // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating() @@ -590,8 +574,6 @@ class WindowSurfacePlacer { if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New wallpaper target=" + wallpaperTarget + ", oldWallpaper=" + oldWallpaper - + ", lower target=" + lowerWallpaperTarget - + ", upper target=" + upperWallpaperTarget + ", openingApps=" + openingApps + ", closingApps=" + closingApps); mService.mAnimateWallpaperWithTarget = false; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index b821f0900e65..40bd3fb41b2f 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -82,7 +82,7 @@ class WindowToken extends WindowContainer<WindowState> { boolean sendingToBottom; // The display this token is on. - private DisplayContent mDisplayContent; + protected DisplayContent mDisplayContent; /** * Compares two child window of this token and returns -1 if the first is lesser than the @@ -168,88 +168,30 @@ class WindowToken extends WindowContainer<WindowState> { return highestAnimLayer; } - WindowState getTopWindow() { - if (mChildren.isEmpty()) { - return null; - } - return (WindowState) mChildren.get(mChildren.size() - 1).getTop(); - } - - /** - * Recursive search through a WindowList and all of its windows' children. - * @param target The window to search for. - * @return The index of win in windows or of the window that is an ancestor of win. - */ - int getWindowIndex(WindowState target) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final WindowState w = mChildren.get(i); - if (w == target || w.hasChild(target)) { - return i; - } - } - return -1; - } - /** * Returns true if the new window is considered greater than the existing window in terms of * z-order. */ protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow) { - // By default the first window isn't greater than the second to preserve existing logic of - // how new windows are added to the token - return false; + // New window is considered greater if it has a higher or equal base layer. + return newWindow.mBaseLayer >= existingWindow.mBaseLayer; } void addWindow(final WindowState win) { if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindow: win=" + win + " Callers=" + Debug.getCallers(5)); - if (!win.isChildWindow()) { - if (asAppWindowToken() != null) { - mDisplayContent.addAppWindowToWindowList(win); - } else { - mDisplayContent.addNonAppWindowToWindowList(win); - } - - if (!mChildren.contains(win)) { - if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this); - addChild(win, mWindowComparator); - } - } else { - mDisplayContent.addChildWindowToWindowList(win); - } - } - - void addImeWindow(WindowState win) { - int pos = mDisplayContent.findDesiredInputMethodWindowIndex(true); - - if (pos < 0) { - addWindow(win); - mDisplayContent.moveInputMethodDialogs(pos); + if (win.isChildWindow()) { + // Child windows are added to their parent windows. return; } - - if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, - "Adding input method window " + win + " at " + pos); - mDisplayContent.addToWindowList(win, pos); if (!mChildren.contains(win)) { - addChild(win, null); - } - mDisplayContent.moveInputMethodDialogs(pos + 1); - } - - /** Return the first window in the token window list that isn't a starting window or null. */ - WindowState getFirstNonStartingWindow() { - final int count = mChildren.size(); - // We only care about parent windows so no need to loop through child windows. - for (int i = 0; i < count; i++) { - final WindowState w = mChildren.get(i); - if (w.mAttrs.type != TYPE_APPLICATION_STARTING) { - return w; - } + if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this); + addChild(win, mWindowComparator); + mService.mWindowsChanged = true; + // TODO: Should we also be setting layout needed here and other places? } - return null; } /** Returns true if the token windows list is empty. */ @@ -280,169 +222,6 @@ class WindowToken extends WindowContainer<WindowState> { return false; } - void hideWallpaperToken(boolean wasDeferred, String reason) { - for (int j = mChildren.size() - 1; j >= 0; j--) { - final WindowState wallpaper = mChildren.get(j); - wallpaper.hideWallpaperWindow(wasDeferred, reason); - } - hidden = true; - } - - void sendWindowWallpaperCommand( - String action, int x, int y, int z, Bundle extras, boolean sync) { - for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { - final WindowState wallpaper = mChildren.get(wallpaperNdx); - try { - wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync); - // We only want to be synchronous with one wallpaper. - sync = false; - } catch (RemoteException e) { - } - } - } - - void updateWallpaperOffset(int dw, int dh, boolean sync) { - final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; - for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { - final WindowState wallpaper = mChildren.get(wallpaperNdx); - if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) { - final WindowStateAnimator winAnimator = wallpaper.mWinAnimator; - winAnimator.computeShownFrameLocked(); - // No need to lay out the windows - we can just set the wallpaper position directly. - winAnimator.setWallpaperOffset(wallpaper.mShownPosition); - // We only want to be synchronous with one wallpaper. - sync = false; - } - } - } - - void updateWallpaperVisibility(boolean visible) { - final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); - final int dw = displayInfo.logicalWidth; - final int dh = displayInfo.logicalHeight; - - if (hidden == visible) { - hidden = !visible; - // Need to do a layout to ensure the wallpaper now has the correct size. - mDisplayContent.setLayoutNeeded(); - } - - final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; - for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { - final WindowState wallpaper = mChildren.get(wallpaperNdx); - if (visible) { - wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false); - } - - wallpaper.dispatchWallpaperVisibility(visible); - } - } - - /** - * Starts {@param anim} on all children. - */ - void startAnimation(Animation anim) { - for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) { - final WindowState windowState = mChildren.get(ndx); - windowState.mWinAnimator.setAnimation(anim); - } - } - - boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windowList, - WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh, - int wallpaperAnimLayerAdj) { - - boolean changed = false; - if (hidden == visible) { - if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, - "Wallpaper token " + token + " hidden=" + !visible); - hidden = !visible; - // Need to do a layout to ensure the wallpaper now has the correct size. - mDisplayContent.setLayoutNeeded(); - } - - final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; - for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { - final WindowState wallpaper = mChildren.get(wallpaperNdx); - - if (visible) { - wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false); - } - - // First, make sure the client has the current visibility state. - wallpaper.dispatchWallpaperVisibility(visible); - wallpaper.adjustAnimLayer(wallpaperAnimLayerAdj); - - if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " - + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); - - // First, if this window is at the current index, then all is well. - if (wallpaper == wallpaperTarget) { - wallpaperTargetIndex--; - wallpaperTarget = wallpaperTargetIndex > 0 - ? windowList.get(wallpaperTargetIndex - 1) : null; - continue; - } - - // The window didn't match... the current wallpaper window, - // wherever it is, is in the wrong place, so make sure it is not in the list. - int oldIndex = windowList.indexOf(wallpaper); - if (oldIndex >= 0) { - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, - "Wallpaper removing at " + oldIndex + ": " + wallpaper); - mDisplayContent.removeFromWindowList(wallpaper); - if (oldIndex < wallpaperTargetIndex) { - wallpaperTargetIndex--; - } - } - - // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost - // layer. For keyguard over wallpaper put the wallpaper under the lowest window that - // is currently on screen, i.e. not hidden by policy. - int insertionIndex = 0; - if (visible && wallpaperTarget != null) { - final int privateFlags = wallpaperTarget.mAttrs.privateFlags; - if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - insertionIndex = Math.min(windowList.indexOf(wallpaperTarget), - findLowestWindowOnScreen(windowList)); - } - } - if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT - || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG, - "Moving wallpaper " + wallpaper + " from " + oldIndex + " to " + insertionIndex); - - mDisplayContent.addToWindowList(wallpaper, insertionIndex); - changed = true; - } - - return changed; - } - - /** - * @return The index in {@param windows} of the lowest window that is currently on screen and - * not hidden by the policy. - */ - private int findLowestWindowOnScreen(ReadOnlyWindowList windowList) { - final int size = windowList.size(); - for (int index = 0; index < size; index++) { - final WindowState win = windowList.get(index); - if (win.isOnScreen()) { - return index; - } - } - return Integer.MAX_VALUE; - } - - boolean hasVisibleNotDrawnWallpaper() { - for (int j = mChildren.size() - 1; j >= 0; --j) { - final WindowState wallpaper = mChildren.get(j); - if (wallpaper.hasVisibleNotDrawnWallpaper()) { - return true; - } - } - return false; - } - int getHighestAnimLayer() { int highest = -1; for (int j = 0; j < mChildren.size(); j++) { diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 3a9ff5fe8734..4d43e8e9c368 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -19,6 +19,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \ $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \ $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \ $(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \ $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \ @@ -37,6 +38,7 @@ LOCAL_C_INCLUDES += \ frameworks/base/libs/hwui \ frameworks/base/core/jni \ frameworks/native/services \ + system/core/libappfuse/include \ system/security/keystore/include \ $(call include-path-for, libhardware)/hardware \ $(call include-path-for, libhardware_legacy)/hardware_legacy \ @@ -44,6 +46,7 @@ LOCAL_C_INCLUDES += \ LOCAL_SHARED_LIBRARIES += \ libandroid_runtime \ libandroidfw \ + libappfuse \ libbinder \ libcutils \ liblog \ @@ -64,13 +67,15 @@ LOCAL_SHARED_LIBRARIES += \ libEGL \ libGLESv2 \ libnetutils \ - libhidl \ + libhidlbase \ + libhidltransport \ libhwbinder \ libutils \ + android.hardware.audio.common@2.0 \ + android.hardware.light@2.0 \ android.hardware.power@1.0 \ + android.hardware.thermal@1.0 \ + android.hardware.tv.cec@1.0 \ + android.hardware.tv.input@1.0 \ android.hardware.vibrator@1.0 \ - android.hardware.light@2.0 \ android.hardware.vr@1.0 \ - android.hardware.audio.common@2.0 \ - android.hardware.tv.input@1.0 \ - android.hardware.thermal@1.0 \ diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index a23fbcbd42c7..0c5729e9b32c 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -21,16 +21,32 @@ #include <JNIHelp.h> #include <ScopedPrimitiveArray.h> -#include <cstring> - +#include <android/hardware/tv/cec/1.0/IHdmiCec.h> +#include <android/hardware/tv/cec/1.0/IHdmiCecCallback.h> +#include <android/hardware/tv/cec/1.0/types.h> #include <android_os_MessageQueue.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> -#include <hardware/hdmi_cec.h> #include <sys/param.h> +#include <utils/Errors.h> #include <utils/Looper.h> #include <utils/RefBase.h> +using ::android::hardware::tv::cec::V1_0::CecLogicalAddress; +using ::android::hardware::tv::cec::V1_0::CecMessage; +using ::android::hardware::tv::cec::V1_0::HdmiPortInfo; +using ::android::hardware::tv::cec::V1_0::HotplugEvent; +using ::android::hardware::tv::cec::V1_0::IHdmiCec; +using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback; +using ::android::hardware::tv::cec::V1_0::MaxLength; +using ::android::hardware::tv::cec::V1_0::OptionKey; +using ::android::hardware::tv::cec::V1_0::Result; +using ::android::hardware::tv::cec::V1_0::SendMessageResult; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; + namespace android { static struct { @@ -40,15 +56,13 @@ static struct { class HdmiCecController { public: - HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj, - const sp<Looper>& looper); - - void init(); + HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper); + ~HdmiCecController(); // Send message to other device. Note that it runs in IO thread. - int sendMessage(const cec_message_t& message); + int sendMessage(const CecMessage& message); // Add a logical address to device. - int addLogicalAddress(cec_logical_address_t address); + int addLogicalAddress(CecLogicalAddress address); // Clear all logical address registered to the device. void clearLogicaladdress(); // Get physical address of device. @@ -59,10 +73,12 @@ public: uint32_t getVendorId(); // Get Port information on all the HDMI ports. jobjectArray getPortInfos(); - // Set a flag and its value. - void setOption(int flag, int value); - // Set audio return channel status. - void setAudioReturnChannel(int port, bool flag); + // Set an option to CEC HAL. + void setOption(OptionKey key, bool enabled); + // Informs CEC HAL about the current system language. + void setLanguage(hidl_string language); + // Enable audio return channel. + void enableAudioReturnChannel(int port, bool flag); // Whether to hdmi device is connected to the given port. bool isConnected(int port); @@ -71,69 +87,48 @@ public: } private: + class HdmiCecCallback : public IHdmiCecCallback { + public: + HdmiCecCallback(HdmiCecController* controller) : mController(controller) {}; + Return<void> onCecMessage(const CecMessage& event) override; + Return<void> onHotplugEvent(const HotplugEvent& event) override; + private: + HdmiCecController* mController; + }; + static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF; - static void onReceived(const hdmi_event_t* event, void* arg); - hdmi_cec_device_t* mDevice; + sp<IHdmiCec> mHdmiCec; jobject mCallbacksObj; + sp<IHdmiCecCallback> mHdmiCecCallback; sp<Looper> mLooper; }; -// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL -// may keep its own lifetime, we need to copy it in order to delegate -// it to service thread. -class CecEventWrapper : public LightRefBase<CecEventWrapper> { -public: - explicit CecEventWrapper(const hdmi_event_t& event) { - // Copy message. - switch (event.type) { - case HDMI_EVENT_CEC_MESSAGE: - mEvent.cec.initiator = event.cec.initiator; - mEvent.cec.destination = event.cec.destination; - mEvent.cec.length = event.cec.length; - std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length); - break; - case HDMI_EVENT_HOT_PLUG: - mEvent.hotplug.connected = event.hotplug.connected; - mEvent.hotplug.port_id = event.hotplug.port_id; - break; - default: - // TODO: add more type whenever new type is introduced. - break; - } - } - - const cec_message_t& cec() const { - return mEvent.cec; - } - - const hotplug_event_t& hotplug() const { - return mEvent.hotplug; - } - - virtual ~CecEventWrapper() {} - -private: - hdmi_event_t mEvent; -}; - // Handler class to delegate incoming message to service thread. class HdmiCecEventHandler : public MessageHandler { public: - HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event) - : mController(controller), - mEventWrapper(event) { - } + enum EventType { + CEC_MESSAGE, + HOT_PLUG + }; + + HdmiCecEventHandler(HdmiCecController* controller, const CecMessage& cecMessage) + : mController(controller), + mCecMessage(cecMessage) {} + + HdmiCecEventHandler(HdmiCecController* controller, const HotplugEvent& hotplugEvent) + : mController(controller), + mHotplugEvent(hotplugEvent) {} virtual ~HdmiCecEventHandler() {} void handleMessage(const Message& message) { switch (message.what) { - case HDMI_EVENT_CEC_MESSAGE: - propagateCecCommand(mEventWrapper->cec()); + case EventType::CEC_MESSAGE: + propagateCecCommand(mCecMessage); break; - case HDMI_EVENT_HOT_PLUG: - propagateHotplugEvent(mEventWrapper->hotplug()); + case EventType::HOT_PLUG: + propagateHotplugEvent(mHotplugEvent); break; default: // TODO: add more type whenever new type is introduced. @@ -143,14 +138,13 @@ public: private: // Propagate the message up to Java layer. - void propagateCecCommand(const cec_message_t& message) { - jint srcAddr = message.initiator; - jint dstAddr = message.destination; + void propagateCecCommand(const CecMessage& message) { JNIEnv* env = AndroidRuntime::getJNIEnv(); - jbyteArray body = env->NewByteArray(message.length); - const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body); - env->SetByteArrayRegion(body, 0, message.length, bodyPtr); - + jint srcAddr = static_cast<jint>(message.initiator); + jint dstAddr = static_cast<jint>(message.destination); + jbyteArray body = env->NewByteArray(message.body.size()); + const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body.data()); + env->SetByteArrayRegion(body, 0, message.body.size(), bodyPtr); env->CallVoidMethod(mController->getCallbacksObj(), gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr, dstAddr, body); @@ -159,10 +153,10 @@ private: checkAndClearExceptionFromCallback(env, __FUNCTION__); } - void propagateHotplugEvent(const hotplug_event_t& event) { + void propagateHotplugEvent(const HotplugEvent& event) { // Note that this method should be called in service thread. JNIEnv* env = AndroidRuntime::getJNIEnv(); - jint port = event.port_id; + jint port = static_cast<jint>(event.portId); jboolean connected = (jboolean) event.connected; env->CallVoidMethod(mController->getCallbacksObj(), gHdmiCecControllerClassInfo.handleHotplug, port, connected); @@ -180,51 +174,83 @@ private: } HdmiCecController* mController; - sp<CecEventWrapper> mEventWrapper; + CecMessage mCecMessage; + HotplugEvent mHotplugEvent; }; -HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, - jobject callbacksObj, const sp<Looper>& looper) : - mDevice(device), - mCallbacksObj(callbacksObj), - mLooper(looper) { +HdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec, + jobject callbacksObj, const sp<Looper>& looper) + : mHdmiCec(hdmiCec), + mCallbacksObj(callbacksObj), + mLooper(looper) { + mHdmiCecCallback = new HdmiCecCallback(this); + Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to set a cec callback."); + } } -void HdmiCecController::init() { - mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this); +HdmiCecController::~HdmiCecController() { + Return<void> ret = mHdmiCec->setCallback(nullptr); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to set a cec callback."); + } } -int HdmiCecController::sendMessage(const cec_message_t& message) { +int HdmiCecController::sendMessage(const CecMessage& message) { // TODO: propagate send_message's return value. - return mDevice->send_message(mDevice, &message); + Return<SendMessageResult> ret = mHdmiCec->sendMessage(message); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to send CEC message."); + return static_cast<int>(SendMessageResult::FAIL); + } + return static_cast<int>((SendMessageResult) ret); } -int HdmiCecController::addLogicalAddress(cec_logical_address_t address) { - return mDevice->add_logical_address(mDevice, address); +int HdmiCecController::addLogicalAddress(CecLogicalAddress address) { + Return<Result> ret = mHdmiCec->addLogicalAddress(address); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to add a logical address."); + return static_cast<int>(Result::FAILURE_UNKNOWN); + } + return static_cast<int>((Result) ret); } void HdmiCecController::clearLogicaladdress() { - mDevice->clear_logical_address(mDevice); + Return<void> ret = mHdmiCec->clearLogicalAddress(); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to clear logical address."); + } } int HdmiCecController::getPhysicalAddress() { + Result result; uint16_t addr; - if (!mDevice->get_physical_address(mDevice, &addr)) { - return addr; + Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) { + result = res; + addr = paddr; + }); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to get physical address."); + return INVALID_PHYSICAL_ADDRESS; } - return INVALID_PHYSICAL_ADDRESS; + return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS; } int HdmiCecController::getVersion() { - int version = 0; - mDevice->get_version(mDevice, &version); - return version; + Return<int32_t> ret = mHdmiCec->getCecVersion(); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to get cec version."); + } + return ret; } uint32_t HdmiCecController::getVendorId() { - uint32_t vendorId = 0; - mDevice->get_vendor_id(mDevice, &vendorId); - return vendorId; + Return<uint32_t> ret = mHdmiCec->getVendorId(); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to get vendor id."); + } + return ret; } jobjectArray HdmiCecController::getPortInfos() { @@ -237,48 +263,69 @@ jobjectArray HdmiCecController::getPortInfos() { if (ctor == NULL) { return NULL; } - hdmi_port_info* ports; - int numPorts; - mDevice->get_port_info(mDevice, &ports, &numPorts); - jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL); + hidl_vec<HdmiPortInfo> ports; + Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { + ports = list; + }); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to get port information."); + return NULL; + } + jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL); // MHL support field will be obtained from MHL HAL. Leave it to false. jboolean mhlSupported = (jboolean) 0; - for (int i = 0; i < numPorts; ++i) { - hdmi_port_info* info = &ports[i]; - jboolean cecSupported = (jboolean) info->cec_supported; - jboolean arcSupported = (jboolean) info->arc_supported; - jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type, - info->physical_address, cecSupported, mhlSupported, arcSupported); + for (size_t i = 0; i < ports.size(); ++i) { + jboolean cecSupported = (jboolean) ports[i].cecSupported; + jboolean arcSupported = (jboolean) ports[i].arcSupported; + jobject infoObj = env->NewObject(hdmiPortInfo, ctor, ports[i].portId, ports[i].type, + ports[i].physicalAddress, cecSupported, mhlSupported, arcSupported); env->SetObjectArrayElement(res, i, infoObj); } return res; } -void HdmiCecController::setOption(int flag, int value) { - mDevice->set_option(mDevice, flag, value); +void HdmiCecController::setOption(OptionKey key, bool enabled) { + Return<void> ret = mHdmiCec->setOption(key, enabled); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to set option."); + } } -// Set audio return channel status. - void HdmiCecController::setAudioReturnChannel(int port, bool enabled) { - mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0); +void HdmiCecController::setLanguage(hidl_string language) { + Return<void> ret = mHdmiCec->setLanguage(language); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to set language."); + } +} + +// Enable audio return channel. +void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) { + Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to enable/disable ARC."); + } } // Whether to hdmi device is connected to the given port. bool HdmiCecController::isConnected(int port) { - return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED; + Return<bool> ret = mHdmiCec->isConnected(port); + if (!ret.getStatus().isOk()) { + ALOGE("Failed to get connection info."); + } + return ret; } -// static -void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { - HdmiCecController* controller = static_cast<HdmiCecController*>(arg); - if (controller == NULL) { - return; - } +Return<void> HdmiCecController::HdmiCecCallback::onCecMessage(const CecMessage& message) { + sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, message)); + mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::CEC_MESSAGE); + return Void(); +} - sp<CecEventWrapper> spEvent(new CecEventWrapper(*event)); - sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent)); - controller->mLooper->sendMessage(handler, event->type); +Return<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) { + sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event)); + mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG); + return Void(); } //------------------------------------------------------------------------------ @@ -288,30 +335,19 @@ void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj, jobject messageQueueObj) { - int err; - hw_module_t* module; - err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, - const_cast<const hw_module_t **>(&module)); - if (err != 0) { - ALOGE("Error acquiring hardware module: %d", err); - return 0; - } - - hw_device_t* device; - err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device); - if (err != 0) { - ALOGE("Error opening hardware module: %d", err); + // TODO(b/31632518) + sp<IHdmiCec> hdmiCec = IHdmiCec::getService("tv.cec"); + if (hdmiCec == nullptr) { + ALOGE("Couldn't get tv.cec service."); return 0; } - sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); HdmiCecController* controller = new HdmiCecController( - reinterpret_cast<hdmi_cec_device*>(device), + hdmiCec, env->NewGlobalRef(callbacksObj), messageQueue->getLooper()); - controller->init(); GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz, "handleIncomingCecCommand", "(II[B)V"); @@ -323,14 +359,18 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj, static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, jint srcAddr, jint dstAddr, jbyteArray body) { - cec_message_t message; - message.initiator = static_cast<cec_logical_address_t>(srcAddr); - message.destination = static_cast<cec_logical_address_t>(dstAddr); + CecMessage message; + message.initiator = static_cast<CecLogicalAddress>(srcAddr); + message.destination = static_cast<CecLogicalAddress>(dstAddr); jsize len = env->GetArrayLength(body); - message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH); ScopedByteArrayRO bodyPtr(env, body); - std::memcpy(message.body, bodyPtr.get(), message.length); + size_t bodyLength = MIN(static_cast<size_t>(len), + static_cast<size_t>(MaxLength::MESSAGE_BODY)); + message.body.resize(bodyLength); + for (size_t i = 0; i < bodyLength; ++i) { + message.body[i] = static_cast<uint8_t>(bodyPtr[i]); + } HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); @@ -340,7 +380,7 @@ static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr, jint logicalAddress) { HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); - return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress)); + return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress)); } static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { @@ -370,13 +410,20 @@ static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controll static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) { HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); - controller->setOption(flag, value); + controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false); +} + +static void nativeSetLanguage(JNIEnv* env, jclass clazz, jlong controllerPtr, jstring language) { + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); + const char *languageStr = env->GetStringUTFChars(language, NULL); + controller->setLanguage(languageStr); + env->ReleaseStringUTFChars(language, languageStr); } -static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr, +static void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port, jboolean enabled) { HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); - controller->setAudioReturnChannel(port, enabled == JNI_TRUE); + controller->enableAudioReturnChannel(port, enabled == JNI_TRUE); } static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) { @@ -398,8 +445,9 @@ static const JNINativeMethod sMethods[] = { { "nativeGetPortInfos", "(J)[Landroid/hardware/hdmi/HdmiPortInfo;", (void *) nativeGetPortInfos }, - { "nativeSetOption", "(JII)V", (void *) nativeSetOption }, - { "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel }, + { "nativeSetOption", "(JIZ)V", (void *) nativeSetOption }, + { "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage }, + { "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel }, { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected }, }; diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp index e6072bb03ccc..a3ab8f67d2fa 100644 --- a/services/core/jni/com_android_server_lights_LightsService.cpp +++ b/services/core/jni/com_android_server_lights_LightsService.cpp @@ -34,6 +34,9 @@ using Brightness = ::android::hardware::light::V2_0::Brightness; using Flash = ::android::hardware::light::V2_0::Flash; using Type = ::android::hardware::light::V2_0::Type; using LightState = ::android::hardware::light::V2_0::LightState; +using Status = ::android::hardware::light::V2_0::Status; +template<typename T> +using Return = ::android::hardware::Return<T>; static sp<ILight> gLight; @@ -108,9 +111,33 @@ static void setLight_native( state.brightnessMode = brightness; + Status status; + { ALOGD_IF_SLOW(50, "Excessive delay setting light"); - gLight->setLight(type, state); + Return<Status> ret = gLight->setLight(type, state); + + // TODO(b/31348667): this is transport specific status + if (!ret.getStatus().isOk()) { + ALOGE("Failed to issue set light command."); + return; + } + + status = static_cast<Status>(ret); // hal status + } + + switch (status) { + case Status::SUCCESS: + break; + case Status::LIGHT_NOT_SUPPORTED: + ALOGE("Light requested not availale on this device."); + break; + case Status::BRIGHTNESS_NOT_SUPPORTED: + ALOGE("Brightness parameter not supported on this device."); + break; + case Status::UNKNOWN: + default: + ALOGE("Unknown error setting light."); } } diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp new file mode 100644 index 000000000000..2f20ecd1954d --- /dev/null +++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp @@ -0,0 +1,71 @@ +/* + * 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 specic language governing permissions and + * limitations under the License. + */ + +// Need to use LOGE_EX. +#define LOG_TAG "AppFuseBridge" + +#include <android_runtime/Log.h> +#include <android-base/logging.h> +#include <core_jni_helpers.h> +#include <libappfuse/FuseBridgeLoop.h> +#include <nativehelper/JNIHelp.h> + +namespace android { +namespace { + +constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge"; +static jclass appFuseClass; +static jmethodID appFuseOnMount; + +class Callback : public fuse::FuseBridgeLoopCallback { + JNIEnv* mEnv; + jobject mSelf; + +public: + Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {} + void OnMount() override { + mEnv->CallVoidMethod(mSelf, appFuseOnMount); + if (mEnv->ExceptionCheck()) { + LOGE_EX(mEnv, nullptr); + mEnv->ExceptionClear(); + } + } +}; + +jboolean com_android_server_storage_AppFuseBridge_start_loop( + JNIEnv* env, jobject self, jint devJavaFd, jint proxyJavaFd) { + Callback callback(env, self); + return fuse::StartFuseBridgeLoop(devJavaFd, proxyJavaFd, &callback); +} + +const JNINativeMethod methods[] = { + { + "native_start_loop", + "(II)Z", + (void *) com_android_server_storage_AppFuseBridge_start_loop + } +}; + +} // namespace + +void register_android_server_storage_AppFuse(JNIEnv* env) { + CHECK(env != nullptr); + + appFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME)); + appFuseOnMount = GetMethodIDOrDie(env, appFuseClass, "onMount", "()V"); + RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods)); +} +} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index d69c37f0afea..c291ba0dc24a 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -28,6 +28,7 @@ int register_android_server_InputWindowHandle(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_PowerManagerService(JNIEnv* env); +int register_android_server_storage_AppFuse(JNIEnv* env); int register_android_server_SerialService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); int register_android_server_UsbDeviceManager(JNIEnv* env); @@ -83,6 +84,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_PersistentDataBlockService(env); register_android_server_Watchdog(env); register_android_server_HardwarePropertiesManagerService(env); + register_android_server_storage_AppFuse(env); return JNI_VERSION_1_4; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 0ea8d4e5101d..c497cb1c4413 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -22,7 +22,7 @@ import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA; import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES; -import static com.android.internal.logging.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; @@ -38,10 +38,11 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.IActivityManager; +import android.app.IApplicationThread; +import android.app.IServiceConnection; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -137,6 +138,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.ParcelableString; @@ -203,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"; @@ -464,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; @@ -490,9 +504,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * to listen for events. */ if (Intent.ACTION_USER_STARTED.equals(action) - && userHandle == mOwners.getDeviceOwnerUserId() - && isNetworkLoggingEnabledInternal()) { - setNetworkLoggingActiveInternal(true); + && userHandle == mOwners.getDeviceOwnerUserId()) { + synchronized (DevicePolicyManagerService.this) { + if (isNetworkLoggingEnabledInternalLocked()) { + setNetworkLoggingActiveInternal(true); + } + } } if (Intent.ACTION_BOOT_COMPLETED.equals(action) && userHandle == mOwners.getDeviceOwnerUserId() @@ -1436,6 +1453,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); } + PackageManager getPackageManager() { + return mContext.getPackageManager(); + } + PowerManagerInternal getPowerManagerInternal() { return LocalServices.getService(PowerManagerInternal.class); } @@ -1450,7 +1471,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } IActivityManager getIActivityManager() { - return ActivityManagerNative.getDefault(); + return ActivityManager.getService(); } IPackageManager getIPackageManager() { @@ -2350,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, @@ -2506,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); @@ -5512,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 { - ActivityManagerNative.getDefault().requestBugReport( + mInjector.getIActivityManager().requestBugReport( ActivityManager.BUGREPORT_OPTION_REMOTE); mRemoteBugreportServiceIsActive.set(true); @@ -5904,6 +5964,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + boolean isDeviceOwner(ActiveAdmin admin) { + return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier()); + } + public boolean isDeviceOwner(ComponentName who, int userId) { synchronized (this) { return mOwners.hasDeviceOwner() @@ -6028,6 +6092,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) { + disableDeviceOwnerManagedSingleUserFeaturesIfNeeded(); if (admin != null) { admin.disableCamera = false; admin.userRestrictions = null; @@ -6039,7 +6104,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mOwners.clearDeviceOwner(); mOwners.writeDeviceOwner(); updateDeviceOwnerLocked(); - disableDeviceOwnerManagedSingleUserFeaturesIfNeeded(); try { if (mInjector.getIBackupManager() != null) { // Reactivate backup service. @@ -6517,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(), @@ -8686,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 { @@ -9156,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); @@ -9165,6 +9246,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } + recordSecurityLogRetrievalTime(); + ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>(); try { SecurityLog.readPreviousEvents(output); @@ -9180,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; } @@ -9425,6 +9510,77 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public boolean bindDeviceAdminServiceAsUser( + @NonNull ComponentName admin, @NonNull IApplicationThread caller, + @Nullable IBinder activtiyToken, @NonNull Intent serviceIntent, + @NonNull IServiceConnection connection, int flags, @UserIdInt int targetUserId) { + if (!mHasFeature) { + return false; + } + Preconditions.checkNotNull(admin); + Preconditions.checkNotNull(caller); + Preconditions.checkNotNull(serviceIntent); + Preconditions.checkNotNull(connection); + final int callingUserId = mInjector.userHandleGetCallingUserId(); + Preconditions.checkArgument(callingUserId != targetUserId, + "target user id must be different from the calling user id"); + + synchronized (this) { + final ActiveAdmin callingAdmin = getActiveAdminForCallerLocked(admin, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + // Ensure the target user is valid. + if (isDeviceOwner(callingAdmin)) { + enforceManagedProfile(targetUserId, "Target user must be a managed profile"); + } else { + // Further lock down to profile owner in managed profile. + enforceManagedProfile(callingUserId, + "Only support profile owner in managed profile."); + if (mOwners.getDeviceOwnerUserId() != targetUserId) { + throw new SecurityException("Target user must be a device owner."); + } + } + } + final long callingIdentity = mInjector.binderClearCallingIdentity(); + try { + if (!mUserManager.isSameProfileGroup(callingUserId, targetUserId)) { + throw new SecurityException( + "Can only bind service across users under the same profile group"); + } + final String targetPackage; + synchronized (this) { + targetPackage = getOwnerPackageNameForUserLocked(targetUserId); + } + // STOPSHIP(b/31952368): Add policy to control which packages can talk. + if (TextUtils.isEmpty(targetPackage) || !targetPackage.equals(admin.getPackageName())) { + throw new SecurityException("Device owner and profile owner must be the same " + + "package in order to communicate."); + } + // Validate and sanitize the incoming service intent. + final Intent sanitizedIntent = + createCrossUserServiceIntent(serviceIntent, targetPackage); + if (sanitizedIntent == null) { + // Fail, cannot lookup the target service. + throw new SecurityException("Invalid intent or failed to look up the service"); + } + // Ask ActivityManager to bind it. Notice that we are binding the service with the + // caller app instead of DevicePolicyManagerService. + try { + return mInjector.getIActivityManager().bindService( + caller, activtiyToken, serviceIntent, + serviceIntent.resolveTypeIfNeeded(mContext.getContentResolver()), + connection, flags, mContext.getOpPackageName(), + targetUserId) != 0; + } catch (RemoteException ex) { + // Same process, should not happen. + } + } finally { + mInjector.binderRestoreCallingIdentity(callingIdentity); + } + // Fail to bind. + return false; + } + /** * Return true if a given user has any accounts that'll prevent installing a device or profile * owner {@code owner}. @@ -9515,7 +9671,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(admin); ensureDeviceOwnerManagingSingleUser(admin); - if (enabled == isNetworkLoggingEnabledInternal()) { + if (enabled == isNetworkLoggingEnabledInternalLocked()) { // already in the requested state return; } @@ -9556,11 +9712,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(admin); synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - return isNetworkLoggingEnabledInternal(); + return isNetworkLoggingEnabledInternalLocked(); } } - private synchronized boolean isNetworkLoggingEnabledInternal() { + private boolean isNetworkLoggingEnabledInternalLocked() { ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); return (deviceOwner != null) && deviceOwner.isNetworkLoggingEnabled; } @@ -9569,9 +9725,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * A maximum of 1200 events are returned, and the total marshalled size is in the order of * 100kB, so returning a List instead of ParceledListSlice is acceptable. * Ideally this would be done with ParceledList, however it only supports homogeneous types. + * + * @see NetworkLoggingHandler#MAX_EVENTS_PER_BATCH */ @Override - public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin) { + public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin, + long batchToken) { if (!mHasFeature) { return null; } @@ -9581,6 +9740,80 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (mNetworkLogger == null) { return null; } - return isNetworkLoggingEnabledInternal() ? mNetworkLogger.retrieveLogs() : 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); + } + + /** + * Return the package name of owner in a given user. + */ + private String getOwnerPackageNameForUserLocked(int userId) { + return getDeviceOwnerUserId() == userId + ? mOwners.getDeviceOwnerPackageName() + : mOwners.getProfileOwnerPackage(userId); + } + + /** + * @param rawIntent Original service intent specified by caller. + * @param expectedPackageName The expected package name in the incoming intent. + * @return Intent that have component explicitly set. {@code null} if the incoming intent + * or target service is invalid. + */ + private Intent createCrossUserServiceIntent ( + @NonNull Intent rawIntent, @NonNull String expectedPackageName) { + if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) { + Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): " + + rawIntent); + return null; + } + ResolveInfo info = mInjector.getPackageManager().resolveService(rawIntent, 0); + if (info == null || info.serviceInfo == null) { + Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent); + return null; + } + if (!expectedPackageName.equals(info.serviceInfo.packageName)) { + Log.e(LOG_TAG, "Only allow to bind service in " + expectedPackageName); + return null; + } + if (info.serviceInfo.exported) { + Log.e(LOG_TAG, "The service must be unexported."); + return null; + } + // It is the system server to bind the service, it would be extremely dangerous if it + // can be exploited to bind any service. Set the component explicitly to make sure we + // do not bind anything accidentally. + 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/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java index 185ccc232aa9..8cb13da07c16 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java @@ -147,7 +147,7 @@ final class NetworkLogger { } } - List<NetworkEvent> retrieveLogs() { - return mNetworkLoggingHandler.retrieveFullLogBatch(); + List<NetworkEvent> retrieveLogs(long batchToken) { + return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java index 96884e6db711..29cc43fbcb21 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java @@ -55,11 +55,16 @@ final class NetworkLoggingHandler extends Handler { private final DevicePolicyManagerService mDpm; // threadsafe as it's Handler's thread confined + @GuardedBy("this") private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<NetworkEvent>(); @GuardedBy("this") private ArrayList<NetworkEvent> mFullBatch; + // each full batch is represented by its token, which the DPC has to provide back to revieve it + @GuardedBy("this") + private long mCurrentFullBatchToken; + NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) { super(looper); mDpm = dpm; @@ -97,17 +102,21 @@ final class NetworkLoggingHandler extends Handler { scheduleBatchFinalization(BATCH_FINALIZATION_TIMEOUT_MS); // notify DO that there's a new non-empty batch waiting if (mFullBatch.size() > 0) { - mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, - /* extras */ null); + mCurrentFullBatchToken++; + Bundle extras = new Bundle(); + extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentFullBatchToken); + extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, mFullBatch.size()); + mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras); } else { mFullBatch = null; } } - synchronized List<NetworkEvent> retrieveFullLogBatch() { - List<NetworkEvent> ret = mFullBatch; - mFullBatch = null; - return ret; + synchronized List<NetworkEvent> retrieveFullLogBatch(long batchToken) { + if (batchToken != mCurrentFullBatchToken) { + return null; + } + return mFullBatch; } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index cc96f565564a..1fc4378de277 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -27,6 +27,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.os.BaseBundle; +import android.os.Binder; import android.os.Build; import android.os.Environment; import android.os.FactoryTest; @@ -40,20 +41,18 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; -import android.os.UserManager; -import android.os.storage.IMountService; -import android.provider.Settings; +import android.os.storage.IStorageManager; +import android.util.BootTimingsTraceLog; import android.util.DisplayMetrics; import android.util.EventLog; -import android.util.Pair; import android.util.Slog; 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; import com.android.internal.policy.EmergencyAffordanceManager; import com.android.internal.widget.ILockSettings; import com.android.server.accessibility.AccessibilityManagerService; @@ -100,8 +99,8 @@ import com.android.server.statusbar.StatusBarManagerService; import com.android.server.storage.DeviceStorageMonitorService; import com.android.server.telecom.TelecomLoaderService; import com.android.server.trust.TrustManagerService; -import com.android.server.tv.TvRemoteService; import com.android.server.tv.TvInputManagerService; +import com.android.server.tv.TvRemoteService; import com.android.server.twilight.TwilightService; import com.android.server.usage.UsageStatsService; import com.android.server.vr.VrManagerService; @@ -110,8 +109,6 @@ import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; -import java.util.ArrayDeque; -import java.util.Deque; import java.io.File; import java.io.IOException; import java.util.Locale; @@ -123,11 +120,8 @@ import static android.view.Display.DEFAULT_DISPLAY; public final class SystemServer { private static final String TAG = "SystemServer"; - private static final boolean LOG_BOOT_TIME = true; - // Debug boot time for every step if it's non-user build. - private static final boolean DEBUG_BOOT_TIME = LOG_BOOT_TIME && !"user".equals(Build.TYPE); - private static final String TAG_BOOT_TIME = "SystemServerTiming"; - private static final Deque<Pair<String, Long>> START_TIMES = new ArrayDeque<>(); + private static final BootTimingsTraceLog BOOT_TIMINGS_TRACE_LOG + = new BootTimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER); private static final String ENCRYPTING_STATE = "trigger_restart_min_framework"; private static final String ENCRYPTED_STATE = "1"; @@ -166,8 +160,8 @@ public final class SystemServer { "com.android.server.job.JobSchedulerService"; private static final String LOCK_SETTINGS_SERVICE_CLASS = "com.android.server.LockSettingsService$Lifecycle"; - private static final String MOUNT_SERVICE_CLASS = - "com.android.server.MountService$Lifecycle"; + private static final String STORAGE_MANAGER_SERVICE_CLASS = + "com.android.server.StorageManagerService$Lifecycle"; private static final String SEARCH_MANAGER_SERVICE_CLASS = "com.android.server.search.SearchManagerService$Lifecycle"; private static final String THERMAL_OBSERVER_CLASS = @@ -184,6 +178,8 @@ public final class SystemServer { "com.android.server.content.ContentService$Lifecycle"; private static final String WALLPAPER_SERVICE_CLASS = "com.android.server.wallpaper.WallpaperManagerService$Lifecycle"; + private static final String AUTO_FILL_MANAGER_SERVICE_CLASS = + "com.android.server.autofill.AutoFillManagerService"; private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; @@ -267,9 +263,19 @@ public final class SystemServer { SystemProperties.set("persist.sys.localevar", ""); } + // The system server should never make non-oneway calls + Binder.setWarnOnBlocking(true); + // 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); + // Also report when first stage of init has started + long initStartNs = SystemProperties.getLong("init.start", -1); + if (initStartNs >= 0) { + MetricsLogger.histogram(null, "boot_android_init", (int)(initStartNs / 1000000)); + } // In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system @@ -358,6 +364,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(); @@ -486,13 +493,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). @@ -566,7 +576,7 @@ public final class SystemServer { private void startOtherServices() { final Context context = mSystemContext; VibratorService vibrator = null; - IMountService mountService = null; + IStorageManager storageManager = null; NetworkManagementService networkManagement = null; NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; @@ -778,17 +788,17 @@ public final class SystemServer { if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { if (!disableStorage && !"0".equals(SystemProperties.get("system_init.startmountservice"))) { - traceBeginAndSlog("StartMountService"); + traceBeginAndSlog("StartStorageManagerService"); try { /* - * NotificationManagerService is dependant on MountService, - * (for media / usb notifications) so we must start MountService first. + * NotificationManagerService is dependant on StorageManagerService, + * (for media / usb notifications) so we must start StorageManagerService first. */ - mSystemServiceManager.startService(MOUNT_SERVICE_CLASS); - mountService = IMountService.Stub.asInterface( + mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS); + storageManager = IStorageManager.Stub.asInterface( ServiceManager.getService("mount")); } catch (Throwable e) { - reportWtf("starting Mount Service", e); + reportWtf("starting StorageManager Service", e); } traceEnd(); } @@ -987,14 +997,14 @@ public final class SystemServer { } /* - * MountService has a few dependencies: Notification Manager and - * AppWidget Provider. Make sure MountService is completely started + * StorageManagerService has a few dependencies: Notification Manager and + * AppWidget Provider. Make sure StorageManagerService is completely started * first before continuing. */ - if (mountService != null && !mOnlyCore) { + if (storageManager != null && !mOnlyCore) { traceBeginAndSlog("WaitForAsecScan"); try { - mountService.waitForAsecScan(); + storageManager.waitForAsecScan(); } catch (RemoteException ignored) { } traceEnd(); @@ -1362,6 +1372,10 @@ public final class SystemServer { mSystemServiceManager.startService(RetailDemoModeService.class); traceEnd(); + traceBeginAndSlog("StartAutoFillService"); + mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS); + traceEnd(); + // It is now time to start up the app processes... traceBeginAndSlog("MakeVibratorServiceReady"); @@ -1626,24 +1640,11 @@ public final class SystemServer { } private static void traceBeginAndSlog(String name) { - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); Slog.i(TAG, name); - if (DEBUG_BOOT_TIME) { - START_TIMES.push(Pair.create(name, Long.valueOf(SystemClock.elapsedRealtime()))); - } + BOOT_TIMINGS_TRACE_LOG.traceBegin(name); } private static void traceEnd() { - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - if (!DEBUG_BOOT_TIME) { - return; - } - Pair<String, Long> event = START_TIMES.pollFirst(); - if (event == null) { - Slog.w(TAG, "traceEnd called more times than traceBeginAndSlog"); - return; - } - Slog.d(TAG_BOOT_TIME, event.first + " took to complete: " - + (SystemClock.elapsedRealtime() - event.second) + "ms"); + BOOT_TIMINGS_TRACE_LOG.traceEnd(); } } diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index 01d93048bfe2..39f14e5ee287 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -631,6 +631,11 @@ public class IpManager extends StateMachine { return shouldLog; } + // TODO: Migrate all Log.e(...) to logError(...). + private void logError(String fmt, Object... args) { + mLocalLog.log("ERROR " + String.format(fmt, args)); + } + private void getNetworkInterface() { try { mNetworkInterface = NetworkInterface.getByName(mInterfaceName); @@ -880,7 +885,7 @@ public class IpManager extends StateMachine { mNwService.setInterfaceConfig(mInterfaceName, ifcg); if (VDBG) Log.d(mTag, "IPv4 configuration succeeded"); } catch (IllegalStateException | RemoteException e) { - Log.e(mTag, "IPv4 configuration failed: ", e); + logError("IPv4 configuration failed: %s", e); return false; } return true; @@ -944,6 +949,12 @@ public class IpManager extends StateMachine { } } + private void doImmediateProvisioningFailure(int failureType) { + if (DBG) { Log.e(mTag, "onProvisioningFailure(): " + failureType); } + recordMetric(failureType); + mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties)); + } + private boolean startIPv4() { // If we have a StaticIpConfiguration attempt to apply it and // handle the result accordingly. @@ -951,9 +962,6 @@ public class IpManager extends StateMachine { if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) { handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); } else { - if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); } - recordMetric(IpManagerEvent.PROVISIONING_FAIL); - mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties)); return false; } } else { @@ -972,16 +980,40 @@ public class IpManager extends StateMachine { mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); mNwService.enableIpv6(mInterfaceName); } catch (RemoteException re) { - Log.e(mTag, "Unable to change interface settings: " + re); + logError("Unable to change interface settings: %s", re); return false; } catch (IllegalStateException ie) { - Log.e(mTag, "Unable to change interface settings: " + ie); + logError("Unable to change interface settings: %s", ie); return false; } return true; } + private boolean startIpReachabilityMonitor() { + try { + mIpReachabilityMonitor = new IpReachabilityMonitor( + mContext, + mInterfaceName, + new IpReachabilityMonitor.Callback() { + @Override + public void notifyLost(InetAddress ip, String logMsg) { + mCallback.onReachabilityLost(logMsg); + } + }, + mAvoidBadWifiTracker); + } catch (IllegalArgumentException iae) { + // Failed to start IpReachabilityMonitor. Log it and call + // onProvisioningFailure() immediately. + // + // See http://b/31038971. + logError("IpReachabilityMonitor failure: %s", iae); + mIpReachabilityMonitor = null; + } + + return (mIpReachabilityMonitor != null); + } + private void stopAllIP() { // We don't need to worry about routes, just addresses, because: // - disableIpv6() will clear autoconf IPv6 routes as well, and @@ -1165,29 +1197,23 @@ public class IpManager extends StateMachine { mCallback.setFallbackMulticastFilter(mMulticastFiltering); } - if (mConfiguration.mEnableIPv6) { - // TODO: Consider transitionTo(mStoppingState) if this fails. - startIPv6(); + if (mConfiguration.mEnableIPv6 && !startIPv6()) { + doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6); + transitionTo(mStoppingState); + return; } - if (mConfiguration.mEnableIPv4) { - if (!startIPv4()) { - transitionTo(mStoppingState); - return; - } + if (mConfiguration.mEnableIPv4 && !startIPv4()) { + doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4); + transitionTo(mStoppingState); + return; } - if (mConfiguration.mUsingIpReachabilityMonitor) { - mIpReachabilityMonitor = new IpReachabilityMonitor( - mContext, - mInterfaceName, - new IpReachabilityMonitor.Callback() { - @Override - public void notifyLost(InetAddress ip, String logMsg) { - mCallback.onReachabilityLost(logMsg); - } - }, - mAvoidBadWifiTracker); + if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) { + doImmediateProvisioningFailure( + IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR); + transitionTo(mStoppingState); + return; } } diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 6558b6e2bbf5..d7666d91b6c3 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -22,7 +22,6 @@ import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; import android.Manifest; import android.annotation.NonNull; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -915,7 +914,7 @@ public final class PrintManagerService extends SystemService { private int resolveCallingUserEnforcingPermissions(int userId) { try { - return ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), + return ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null); } catch (RemoteException re) { // Shouldn't happen, local. diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java index 07b26e83e934..f4c9c86fda2a 100644 --- a/services/print/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java @@ -43,9 +43,13 @@ import android.printservice.PrintService; import android.util.Slog; import android.util.TimedRemoteCaller; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.TransferPipe; + import libcore.io.IoUtils; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.List; @@ -109,6 +113,10 @@ final class RemotePrintSpooler { private boolean mCanUnbind; + /** Whether a thread is currently trying to {@link #bindLocked() bind to the print service} */ + @GuardedBy("mLock") + private boolean mIsBinding; + public static interface PrintSpoolerCallbacks { public void onPrintJobQueued(PrintJobInfo printJob); public void onAllPrintJobsForServiceHandled(ComponentName printService); @@ -161,10 +169,8 @@ final class RemotePrintSpooler { try { return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(), componentName, state, appId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error getting print jobs.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error getting print jobs.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error getting print jobs.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()"); @@ -185,10 +191,8 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().createPrintJob(printJob); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error creating print job.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error creating print job.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error creating print job.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()"); @@ -208,10 +212,8 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().writePrintJobData(fd, printJobId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error writing print job data.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error writing print job data.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error writing print job data.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()"); @@ -235,10 +237,8 @@ final class RemotePrintSpooler { try { return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(), printJobId, appId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error getting print job info.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error getting print job info.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error getting print job info.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()"); @@ -260,10 +260,8 @@ final class RemotePrintSpooler { try { return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(), printJobId, state, error); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting print job state.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error setting print job state.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error setting print job state.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()"); @@ -291,7 +289,7 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().setProgress(printJobId, progress); - } catch (RemoteException|TimeoutException re) { + } catch (RemoteException | TimeoutException | InterruptedException re) { Slog.e(LOG_TAG, "Error setting progress.", re); } finally { if (DEBUG) { @@ -318,8 +316,8 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().setStatus(printJobId, status); - } catch (RemoteException|TimeoutException re) { - Slog.e(LOG_TAG, "Error setting status.", re); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error setting status.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setStatus()"); @@ -347,8 +345,8 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().setStatusRes(printJobId, status, appPackageName); - } catch (RemoteException|TimeoutException re) { - Slog.e(LOG_TAG, "Error setting status.", re); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error setting status.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setStatus()"); @@ -377,7 +375,7 @@ final class RemotePrintSpooler { try { mCustomPrinterIconLoadedCaller.onCustomPrinterIconLoaded(getRemoteInstanceLazy(), printerId, icon); - } catch (RemoteException|TimeoutException re) { + } catch (RemoteException | TimeoutException | InterruptedException re) { Slog.e(LOG_TAG, "Error loading new custom printer icon.", re); } finally { if (DEBUG) { @@ -409,8 +407,8 @@ final class RemotePrintSpooler { try { return mGetCustomPrinterIconCaller.getCustomPrinterIcon(getRemoteInstanceLazy(), printerId); - } catch (RemoteException|TimeoutException re) { - Slog.e(LOG_TAG, "Error getting custom printer icon.", re); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error getting custom printer icon.", e); return null; } finally { if (DEBUG) { @@ -435,8 +433,8 @@ final class RemotePrintSpooler { } try { mClearCustomPrinterIconCache.clearCustomPrinterIconCache(getRemoteInstanceLazy()); - } catch (RemoteException|TimeoutException re) { - Slog.e(LOG_TAG, "Error clearing custom printer icon cache.", re); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error clearing custom printer icon cache.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, @@ -459,10 +457,8 @@ final class RemotePrintSpooler { try { return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(), printJobId, tag); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting print job tag.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error setting print job tag.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error setting print job tag.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()"); @@ -484,10 +480,8 @@ final class RemotePrintSpooler { try { getRemoteInstanceLazy().setPrintJobCancelling(printJobId, cancelling); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting print job cancelling.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error setting print job cancelling.", te); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error setting print job cancelling.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() @@ -513,8 +507,8 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().pruneApprovedPrintServices(servicesToKeep); - } catch (RemoteException|TimeoutException re) { - Slog.e(LOG_TAG, "Error pruning approved print services.", re); + } catch (RemoteException | TimeoutException | InterruptedException e) { + Slog.e(LOG_TAG, "Error pruning approved print services.", e); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() @@ -535,9 +529,7 @@ final class RemotePrintSpooler { } try { getRemoteInstanceLazy().removeObsoletePrintJobs(); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re); - } catch (TimeoutException te) { + } catch (RemoteException | TimeoutException | InterruptedException te) { Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te); } finally { if (DEBUG) { @@ -572,13 +564,11 @@ final class RemotePrintSpooler { .append((mRemoteInstance != null) ? "true" : "false").println(); pw.flush(); - try { - getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix}); - } catch (TimeoutException te) { - /* ignore */ - } catch (RemoteException re) { - /* ignore */ + TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd, + new String[] { prefix }); + } catch (IOException | TimeoutException | RemoteException | InterruptedException e) { + pw.println("Failed to dump remote instance: " + e); } } } @@ -594,7 +584,7 @@ final class RemotePrintSpooler { mCallbacks.onPrintJobStateChanged(printJob); } - private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException { + private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException, InterruptedException { synchronized (mLock) { if (mRemoteInstance != null) { return mRemoteInstance; @@ -604,43 +594,50 @@ final class RemotePrintSpooler { } } - private void bindLocked() throws TimeoutException { + private void bindLocked() throws TimeoutException, InterruptedException { + while (mIsBinding) { + mLock.wait(); + } + if (mRemoteInstance != null) { return; } + + mIsBinding = true; + if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked() " + (mIsLowPriority ? "low priority" : "")); } - int flags; - if (mIsLowPriority) { - flags = Context.BIND_AUTO_CREATE; - } else { - flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; - } + try { + int flags; + if (mIsLowPriority) { + flags = Context.BIND_AUTO_CREATE; + } else { + flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; + } - mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, mUserHandle); + mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, mUserHandle); - final long startMillis = SystemClock.uptimeMillis(); - while (true) { - if (mRemoteInstance != null) { - break; - } - final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; - final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis; - if (remainingMillis <= 0) { - throw new TimeoutException("Cannot get spooler!"); - } - try { + final long startMillis = SystemClock.uptimeMillis(); + while (true) { + if (mRemoteInstance != null) { + break; + } + final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; + final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis; + if (remainingMillis <= 0) { + throw new TimeoutException("Cannot get spooler!"); + } mLock.wait(remainingMillis); - } catch (InterruptedException ie) { - /* ignore */ } - } - mCanUnbind = true; - mLock.notifyAll(); + mCanUnbind = true; + } finally { + mIsBinding = false; + mLock.notifyAll(); + } } private void unbindLocked() { diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java index 65c740f9ca3e..7474a64c32cb 100644 --- a/services/print/java/com/android/server/print/UserState.java +++ b/services/print/java/com/android/server/print/UserState.java @@ -68,7 +68,7 @@ import android.util.SparseArray; import com.android.internal.R; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.server.print.RemotePrintService.PrintServiceCallbacks; diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java index 7c7c299710f0..785c3fa7ed5b 100644 --- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java +++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java @@ -17,8 +17,8 @@ package com.android.server.retaildemo; import android.Manifest; +import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.Notification; import android.app.NotificationManager; @@ -591,7 +591,7 @@ public class RetailDemoModeService extends SystemService { void switchUser(int userId) { if (mAms == null) { - mAms = (ActivityManagerService) ActivityManagerNative.getDefault(); + mAms = (ActivityManagerService) ActivityManager.getService(); } mAms.switchUser(userId); } 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 4570a4b432a8..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,11 +228,10 @@ public class BuzzBeepBlinkTest { if (insistent) { n.flags |= Notification.FLAG_INSISTENT; } - StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid, - mScore, n, mUser, System.currentTimeMillis()); - NotificationRecord r = new NotificationRecord(getContext(), sbn, - new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "misc", - NotificationManager.IMPORTANCE_DEFAULT)); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, id, mTag, mUid, + mPid, n, mUser, null, System.currentTimeMillis()); + NotificationRecord r = new NotificationRecord(getContext(), sbn); mService.addNotification(r); return r; } @@ -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/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java index 22b674b93b09..6c3f44778ae6 100644 --- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java @@ -31,6 +31,7 @@ import org.mockito.MockitoAnnotations; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.os.UserHandle; @@ -68,7 +69,10 @@ public class GroupHelperTest { if (groupKey != null) { nb.setGroup(groupKey); } - return new StatusBarNotification(pkg, pkg, id, tag, 0, 0, 0, nb.build(), user); + NotificationChannel channel = + new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_LOW); + return new StatusBarNotification(pkg, pkg, channel, id, tag, 0, 0, nb.build(), user, null, + System.currentTimeMillis()); } private StatusBarNotification getSbn(String pkg, int id, String tag, diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java index 305b5e0acd84..6bc96754e200 100644 --- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java +++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java @@ -69,9 +69,9 @@ public class ImportanceExtractorTest { .setDefaults(Notification.DEFAULT_SOUND); Notification n = builder.build(); - StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid, - mPid, mScore, n, mUser, System.currentTimeMillis()); - NotificationRecord r = new NotificationRecord(getContext(), sbn, channel); + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, mId, mTag, mUid, + mPid, n, mUser, null, System.currentTimeMillis()); + NotificationRecord r = new NotificationRecord(getContext(), sbn); return r; } 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 629146f19006..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; @@ -98,8 +97,8 @@ public class RankingHelperTest { .setWhen(1205) .build(); mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification( - "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user), - getDefaultChannel()); + "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiGroupGSortA, user, + null, System.currentTimeMillis())); mNotiGroupGSortB = new Notification.Builder(getContext()) .setContentTitle("B") @@ -108,24 +107,24 @@ public class RankingHelperTest { .setWhen(1200) .build(); mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification( - "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user), - getDefaultChannel()); + "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiGroupGSortB, user, + null, System.currentTimeMillis())); mNotiNoGroup = new Notification.Builder(getContext()) .setContentTitle("C") .setWhen(1201) .build(); mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification( - "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user), - getDefaultChannel()); + "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroup, user, + null, System.currentTimeMillis())); mNotiNoGroup2 = new Notification.Builder(getContext()) .setContentTitle("D") .setWhen(1202) .build(); mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification( - "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user), - getDefaultChannel()); + "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroup2, user, + null, System.currentTimeMillis())); mNotiNoGroupSortA = new Notification.Builder(getContext()) .setContentTitle("E") @@ -133,8 +132,8 @@ public class RankingHelperTest { .setSortKey("A") .build(); mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification( - "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user), - getDefaultChannel()); + "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroupSortA, user, + null, System.currentTimeMillis())); final ApplicationInfo legacy = new ApplicationInfo(); legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; @@ -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/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java index ffc45ea96e91..7a3ee7f4c068 100644 --- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java @@ -178,9 +178,13 @@ public class SnoozeHelperTest { .setWhen(1205) .build(); return new NotificationRecord(getContext(), new StatusBarNotification( - pkg, pkg, id, tag, 0, 0, 0, n, user), - new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", - NotificationManager.IMPORTANCE_HIGH)); + pkg, pkg, getDefaultChannel(), id, tag, 0, 0, n, user, null, + System.currentTimeMillis())); + } + + private NotificationChannel getDefaultChannel() { + return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", + NotificationManager.IMPORTANCE_LOW); } } diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java new file mode 100644 index 000000000000..d6ee367e0bbd --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server; + +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; + +import static com.android.internal.widget.LockPatternUtils.stringToPattern; + +import static junit.framework.Assert.*; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import static java.io.FileDescriptor.*; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Binder; +import android.os.Debug; +import android.os.Handler; +import android.os.Looper; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.internal.widget.LockPatternUtils; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.FileDescriptor; + +/** + * Test class for {@link LockSettingsShellCommand}. + * + * runtest frameworks-services -c com.android.server.LockSettingsShellCommandTest + */ +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class LockSettingsShellCommandTest { + + private LockSettingsShellCommand mCommand; + + private @Mock LockPatternUtils mLockPatternUtils; + private int mUserId; + private final Binder mBinder = new Binder(); + private final ShellCallback mShellCallback = new ShellCallback(); + private final ResultReceiver mResultReceiver = new ResultReceiver( + new Handler(Looper.getMainLooper())); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + final Context context = InstrumentationRegistry.getTargetContext(); + mUserId = ActivityManager.getCurrentUser(); + mCommand = new LockSettingsShellCommand(context, mLockPatternUtils); + } + + @Test + public void testWrongPassword() throws Exception { + when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); + when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false); + assertEquals(-1, mCommand.exec(mBinder, in, out, err, + new String[] { "set-pin", "--old", "1234" }, + mShellCallback, mResultReceiver)); + verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt()); + } + + @Test + public void testChangePin() throws Exception { + when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); + when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true); + assertEquals(0, mCommand.exec(new Binder(), in, out, err, + new String[] { "set-pin", "--old", "1234", "4321" }, + mShellCallback, mResultReceiver)); + verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC, + mUserId); + } + + @Test + public void testChangePassword() throws Exception { + when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); + when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true); + assertEquals(0, mCommand.exec(new Binder(), in, out, err, + new String[] { "set-password", "--old", "1234", "4321" }, + mShellCallback, mResultReceiver)); + verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC, + mUserId); + } + + @Test + public void testChangePattern() throws Exception { + when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); + when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); + when(mLockPatternUtils.checkPattern(stringToPattern("1234"), mUserId)).thenReturn(true); + assertEquals(0, mCommand.exec(new Binder(), in, out, err, + new String[] { "set-pattern", "--old", "1234", "4321" }, + mShellCallback, mResultReceiver)); + verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId); + } + + @Test + public void testClear() throws Exception { + when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true); + when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false); + when(mLockPatternUtils.checkPattern(stringToPattern("1234"), mUserId)).thenReturn(true); + assertEquals(0, mCommand.exec(new Binder(), in, out, err, + new String[] { "clear", "--old", "1234" }, + mShellCallback, mResultReceiver)); + verify(mLockPatternUtils).clearLock(mUserId); + } +} diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 42d94124d0fe..3114f3fc2b26 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -246,7 +246,8 @@ public class NetworkPolicyManagerServiceTest { Log.d(TAG, "set mUidObserver to " + mUidObserver); return null; } - }).when(mActivityManager).registerUidObserver(any(), anyInt(), null); + }).when(mActivityManager).registerUidObserver(any(), anyInt(), + ActivityManager.PROCESS_STATE_UNKNOWN, null); mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService, mNetworkManager, mIpm, mTime, mPolicyDir, true); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java index bd9e6d19269b..ba25b1659bd2 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java @@ -17,7 +17,6 @@ package com.android.server.am; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.os.ServiceManager; import android.os.UserHandle; @@ -32,7 +31,7 @@ public class ActivityManagerTest extends AndroidTestCase { @Override public void setUp() throws Exception { super.setUp(); - service = ActivityManagerNative.getDefault(); + service = ActivityManager.getService(); } public void testTaskIdsForRunningUsers() throws RemoteException { @@ -52,4 +51,4 @@ public class ActivityManagerTest extends AndroidTestCase { } } } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java index c9c691d1dbd3..0359096892bb 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.app.Activity; +import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.ITaskStackListener; import android.app.Instrumentation.ActivityMonitor; @@ -63,7 +63,7 @@ public class TaskStackChangedListenerTest { @Before public void setUp() throws Exception { - mService = ActivityManagerNative.getDefault(); + mService = ActivityManager.getService(); } @After 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/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 792f3001c049..9f01773eea10 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -737,6 +737,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { // Start the service. initService(); setCaller(CALLING_PACKAGE_1); + + if (ENABLE_DUMP) { + Log.d(TAG, "setUp done"); + } } private static boolean b(Boolean value) { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java new file mode 100644 index 000000000000..379d4fe00afb --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java @@ -0,0 +1,104 @@ +/* + * 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.pm; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PermissionInfo; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.ArraySet; + +import com.android.internal.os.RoSystemProperties; +import com.android.server.SystemConfig; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static junit.framework.Assert.assertTrue; + + +/** + * Presubmit tests for {@link PackageManager}. + */ +@RunWith(AndroidJUnit4.class) +public class PackageManagerPresubmitTest { + + private Context mContext; + + private PackageManager mPackageManager; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getContext(); + mPackageManager = mContext.getPackageManager(); + } + + /** + * <p>This test ensures that all signature|privileged permissions are granted to core apps like + * systemui/settings. If CONTROL_PRIVAPP_PERMISSIONS is set, the test also verifies that + * granted permissions are whitelisted in {@link SystemConfig} + */ + @Test + @SmallTest + @Presubmit + public void testPrivAppPermissions() throws PackageManager.NameNotFoundException { + String[] testPackages = {"com.android.settings", "com.android.shell", + "com.android.systemui"}; + for (String testPackage : testPackages) { + testPackagePrivAppPermission(testPackage); + } + } + + private void testPackagePrivAppPermission(String testPackage) + throws PackageManager.NameNotFoundException { + PackageInfo packageInfo = mPackageManager.getPackageInfo(testPackage, + PackageManager.GET_PERMISSIONS); + ArraySet<String> privAppPermissions = SystemConfig.getInstance() + .getPrivAppPermissions(testPackage); + for (int i = 0; i < packageInfo.requestedPermissions.length; i++) { + String pName = packageInfo.requestedPermissions[i]; + int protectionLevel; + boolean platformPermission; + try { + PermissionInfo permissionInfo = mPackageManager.getPermissionInfo(pName, 0); + platformPermission = PackageManagerService.PLATFORM_PACKAGE_NAME.equals( + permissionInfo.packageName); + protectionLevel = permissionInfo.protectionLevel; + } catch (PackageManager.NameNotFoundException e) { + continue; + } + if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) { + boolean granted = (packageInfo.requestedPermissionsFlags[i] + & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; + assertTrue("Permission " + pName + " should be granted to " + testPackage, granted); + // if CONTROL_PRIVAPP_PERMISSIONS enabled, platform permissions must be whitelisted + // in SystemConfig + if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS) { + assertTrue("Permission " + pName + + " should be declared in the xml file for package " + + testPackage, + privAppPermissions.contains(pName)); + } + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 3cfdc329a971..771ca1467d61 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -4181,7 +4181,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(START_TIME, findShortcut(shortcuts.getValue(), "s4").getLastChangedTimestamp()); - // Next, send unlock even on user-10. Now we scan packages on this user and send a + // Next, send an unlock event on user-10. Now we scan packages on this user and send a // notification to the launcher. mInjectedCurrentTimeMillis = START_TIME + 200; @@ -4222,9 +4222,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageVersion(CALLING_PACKAGE_2, 10); // Then send the broadcast, to only user-0. - mService.mPackageMonitor.onReceive(getTestContext(), + mService.mPackageMonitor.onReceive(getTestContext(), genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0)); - mService.checkPackageChanges(USER_10); waitOnMainThread(); @@ -4395,7 +4394,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Next. - // Update the build finger print. All system apps will be scanned now. + // Update the build finger print. All apps will be scanned now. mInjectedBuildFingerprint = "update1"; mInjectedCurrentTimeMillis += 1000; mService.checkPackageChanges(USER_0); @@ -4406,12 +4405,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { assertWith(getCallerShortcuts()) - .isEmpty(); + .haveIds("ms1"); }); // Next. // Update manifest shortcuts. - mInjectedBuildFingerprint = "update2"; addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_2); @@ -4421,35 +4419,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mInjectedCurrentTimeMillis += 1000; mService.checkPackageChanges(USER_0); - // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned. + // Fingerprint hasn't changed, so there packages weren't scanned. runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertWith(getCallerShortcuts()) .haveIds("ms1"); }); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { assertWith(getCallerShortcuts()) - .isEmpty(); - }); - - // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so - // still not scanned. - mInjectedBuildFingerprint = "update2"; - mInjectedCurrentTimeMillis += 1000; - mService.checkPackageChanges(USER_0); - - runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertWith(getCallerShortcuts()) .haveIds("ms1"); }); - runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { - assertWith(getCallerShortcuts()) - .isEmpty(); - }); - // Now update the version code, so CALLING_PACKAGE_1 is scanned again. - mInjectedBuildFingerprint = "update3"; + // Update the fingerprint. CALLING_PACKAGE_1's version code hasn't changed, but we scan + // all apps anyway. + mInjectedBuildFingerprint = "update2"; mInjectedCurrentTimeMillis += 1000; - updatePackageVersion(CALLING_PACKAGE_1, 1); mService.checkPackageChanges(USER_0); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -4458,7 +4441,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { assertWith(getCallerShortcuts()) - .isEmpty(); + .haveIds("ms1", "ms2"); }); // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted. @@ -5721,6 +5704,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { R.xml.shortcut_5); // Unlock user-0. + mInjectedCurrentTimeMillis += 100; mService.handleUnlockUser(USER_0); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -5750,6 +5734,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { uninstallPackage(USER_10, CALLING_PACKAGE_1); uninstallPackage(USER_10, CALLING_PACKAGE_3); + mInjectedCurrentTimeMillis += 100; mService.handleUnlockUser(USER_10); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -5774,6 +5759,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // hasn't changed. shutdownServices(); + mInjectedCurrentTimeMillis += 100; + addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_5); @@ -5785,7 +5772,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mService.handleUnlockUser(USER_0); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( + assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( // FAIL mManager.getManifestShortcuts()))), "ms1"); assertEmpty(mManager.getPinnedShortcuts()); @@ -5808,6 +5795,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Do it again, but this time we change the app version, so we do detect the changes. shutdownServices(); + mInjectedCurrentTimeMillis += 100; + updatePackageVersion(CALLING_PACKAGE_1, 1); updatePackageLastUpdateTime(CALLING_PACKAGE_3, 1); @@ -5870,6 +5859,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { shutdownServices(); + mInjectedCurrentTimeMillis += 100; + addManifestShortcutResource( new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()), R.xml.shortcut_0); diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index d933cb377ef0..207939fc9dd9 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -33,12 +33,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** - * Tests for the {@link WindowState} class. + * Tests for the {@link AppWindowToken} class. * * Build/Install/Run: * bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests @@ -46,16 +45,7 @@ import static org.junit.Assert.assertTrue; @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class AppWindowTokenTests { - - private static WindowManagerService sWm = null; - private final IWindow mIWindow = new TestIWindow(); - - @Before - public void setUp() throws Exception { - final Context context = InstrumentationRegistry.getTargetContext(); - sWm = TestWindowManagerPolicy.getWindowManagerService(context); - } +public class AppWindowTokenTests extends WindowTestsBase { @Test public void testAddWindow_Order() throws Exception { @@ -63,10 +53,11 @@ public class AppWindowTokenTests { assertEquals(0, token.getWindowsCount()); - final WindowState win1 = createWindow(null, TYPE_APPLICATION, token); - final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token); - final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token); - final WindowState win4 = createWindow(null, TYPE_APPLICATION, token); + final WindowState win1 = createWindow(null, TYPE_APPLICATION, token, "win1"); + final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token, + "startingWin"); + final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin"); + final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4"); token.addWindow(win1); token.addWindow(startingWin); @@ -93,24 +84,18 @@ public class AppWindowTokenTests { assertNull(token.findMainWindow()); - final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token); - final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token); + final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1"); + final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11"); + final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12"); token.addWindow(window1); assertEquals(window1, token.findMainWindow()); window1.mAnimatingExit = true; assertEquals(window1, token.findMainWindow()); - final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token); + final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2"); token.addWindow(window2); assertEquals(window2, token.findMainWindow()); } - private WindowState createWindow(WindowState parent, int type, WindowToken token) { - final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); - - return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0, 0); - } - /* Used so we can gain access to some protected members of the {@link AppWindowToken} class */ private class TestAppWindowToken extends AppWindowToken { diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java new file mode 100644 index 000000000000..0801a883177d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import java.util.ArrayList; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static org.junit.Assert.assertEquals; + +/** + * Tests for the {@link DisplayContent} class. + * + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests + */ +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class DisplayContentTests extends WindowTestsBase { + + @Test + public void testForAllWindows() throws Exception { + final DisplayContent dc = new DisplayContent(mDisplay, sWm, null, null); + final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, dc, "wallpaper"); + final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, dc, "ime"); + final WindowState imeDialogWindow = createWindow(null, TYPE_INPUT_METHOD_DIALOG, dc, + "ime dialog"); + final WindowState statusBarWindow = createWindow(null, TYPE_STATUS_BAR, dc, "status bar"); + final WindowState navBarWindow = createWindow(null, TYPE_NAVIGATION_BAR, + statusBarWindow.mToken, "nav bar"); + final WindowState appWindow = createWindow(null, TYPE_BASE_APPLICATION, dc, "app"); + final WindowState negChildAppWindow = createWindow(appWindow, TYPE_APPLICATION_MEDIA, + appWindow.mToken, "negative app child"); + final WindowState posChildAppWindow = createWindow(appWindow, + TYPE_APPLICATION_ATTACHED_DIALOG, appWindow.mToken, "positive app child"); + final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION, dc, + "exiting app"); + final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken; + exitingAppToken.mIsExiting = true; + exitingAppToken.mTask.mStack.mExitingAppTokens.add(exitingAppToken); + + final ArrayList<WindowState> windows = new ArrayList(); + + // Test forward traversal. + dc.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */); + + assertEquals(wallpaperWindow, windows.get(0)); + assertEquals(exitingAppWindow, windows.get(1)); + assertEquals(negChildAppWindow, windows.get(2)); + assertEquals(appWindow, windows.get(3)); + assertEquals(posChildAppWindow, windows.get(4)); + assertEquals(statusBarWindow, windows.get(5)); + assertEquals(navBarWindow, windows.get(6)); + assertEquals(imeWindow, windows.get(7)); + assertEquals(imeDialogWindow, windows.get(8)); + + // Test backward traversal. + windows.clear(); + dc.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */); + + assertEquals(wallpaperWindow, windows.get(8)); + assertEquals(exitingAppWindow, windows.get(7)); + assertEquals(negChildAppWindow, windows.get(6)); + assertEquals(appWindow, windows.get(5)); + assertEquals(posChildAppWindow, windows.get(4)); + assertEquals(statusBarWindow, windows.get(3)); + assertEquals(navBarWindow, windows.get(2)); + assertEquals(imeWindow, windows.get(1)); + assertEquals(imeDialogWindow, windows.get(0)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 38a98b26d5f1..ed4c79f91ba2 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -272,22 +272,26 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) { + public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { return 0; } @Override - public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) { + public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { return 0; } @Override - public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) { + public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { return 0; } @Override - public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) { + public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, + int displayId) { return 0; } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java new file mode 100644 index 000000000000..5a035d636443 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; + +/** + * Tests for the {@link WindowLayersController} class. + * + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.wm.WindowLayersControllerTests + */ +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class WindowLayersControllerTests extends WindowTestsBase { + + private static boolean sOneTimeSetupDone = false; + private static WindowLayersController sLayersController; + private static DisplayContent sDisplayContent; + private static WindowState sImeWindow; + private static WindowState sImeDialogWindow; + private static WindowState sStatusBarWindow; + private static WindowState sDockedDividerWindow; + private static WindowState sNavBarWindow; + private static WindowState sAppWindow; + private static WindowState sChildAppWindow; + + @Before + public void setUp() throws Exception { + super.setUp(); + + if (sOneTimeSetupDone) { + return; + } + sOneTimeSetupDone = true; + sLayersController = new WindowLayersController(sWm); + sDisplayContent = + new DisplayContent(mDisplay, sWm, sLayersController, new WallpaperController(sWm)); + final WindowState wallpaperWindow = + createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow"); + sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow"); + sImeDialogWindow = + createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow"); + sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow"); + sNavBarWindow = + createWindow(null, TYPE_NAVIGATION_BAR, sStatusBarWindow.mToken, "sNavBarWindow"); + sDockedDividerWindow = + createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow"); + sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow"); + sChildAppWindow = createWindow(sAppWindow, + TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindow"); + } + + @Test + public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception { + sWm.mInputMethodTarget = null; + sLayersController.assignWindowLayers(sDisplayContent); + + // The Ime has an higher base layer than app windows and lower base layer than system + // windows, so it should be above app windows and below system windows if there isn't an IME + // target. + assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow); + assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow); + assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow); + + // And, IME dialogs should always have an higher layer than the IME. + assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow); + } + + @Test + public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception { + final WindowState imeAppTarget = + createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget"); + sWm.mInputMethodTarget = imeAppTarget; + sLayersController.assignWindowLayers(sDisplayContent); + + // Ime should be above all app windows and below system windows if it is targeting an app + // window. + assertWindowLayerGreaterThan(sImeWindow, imeAppTarget); + assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow); + assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow); + assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow); + + // And, IME dialogs should always have an higher layer than the IME. + assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow); + } + + @Test + public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception { + final WindowState imeSystemOverlayTarget = + createWindow(null, TYPE_SYSTEM_OVERLAY, sDisplayContent, "imeSystemOverlayTarget"); + + sWm.mInputMethodTarget = imeSystemOverlayTarget; + sLayersController.assignWindowLayers(sDisplayContent); + + // The IME target base layer is higher than all window except for the nav bar window, so the + // IME should be above all windows except for the nav bar. + assertWindowLayerGreaterThan(sImeWindow, imeSystemOverlayTarget); + assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow); + assertWindowLayerGreaterThan(sImeWindow, sStatusBarWindow); + assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow); + + // And, IME dialogs should always have an higher layer than the IME. + assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow); + } + + private void assertWindowLayerGreaterThan(WindowState first, WindowState second) + throws Exception { + assertGreaterThan(first.mWinAnimator.mAnimLayer, second.mWinAnimator.mAnimLayer); + } + +} diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java index 3df1df980a26..3f47d5cfc2d3 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -41,32 +41,30 @@ import static org.junit.Assert.assertTrue; /** * Tests for the {@link WindowState} class. * - * Build: mmma -j32 frameworks/base/services/tests/servicestests - * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk - * Run: adb shell am instrument -w -e class com.android.server.wm.WindowStateTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner + * runtest frameworks-services -c com.android.server.wm.WindowStateTests */ @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class WindowStateTests { +public class WindowStateTests extends WindowTestsBase { - private static WindowManagerService sWm = null; private WindowToken mWindowToken; - private final IWindow mIWindow = new TestIWindow(); @Before public void setUp() throws Exception { - final Context context = InstrumentationRegistry.getTargetContext(); - sWm = TestWindowManagerPolicy.getWindowManagerService(context); + super.setUp(); mWindowToken = new WindowToken(sWm, new Binder(), 0, false, sWm.getDefaultDisplayContentLocked()); } @Test public void testIsParentWindowHidden() throws Exception { - final WindowState parentWindow = createWindow(null, TYPE_APPLICATION); - final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW); - final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW); + final WindowState parentWindow = + createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow"); + final WindowState child1 = + createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1"); + final WindowState child2 = + createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2"); assertFalse(parentWindow.mHidden); assertFalse(parentWindow.isParentWindowHidden()); @@ -81,10 +79,14 @@ public class WindowStateTests { @Test public void testIsChildWindow() throws Exception { - final WindowState parentWindow = createWindow(null, TYPE_APPLICATION); - final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW); - final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW); - final WindowState randomWindow = createWindow(null, TYPE_APPLICATION); + final WindowState parentWindow = + createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow"); + final WindowState child1 = + createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1"); + final WindowState child2 = + createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2"); + final WindowState randomWindow = + createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow"); assertFalse(parentWindow.isChildWindow()); assertTrue(child1.isChildWindow()); @@ -94,12 +96,13 @@ public class WindowStateTests { @Test public void testHasChild() throws Exception { - final WindowState win1 = createWindow(null, TYPE_APPLICATION); - final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW); - final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW); - final WindowState win2 = createWindow(null, TYPE_APPLICATION); - final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW); - final WindowState randomWindow = createWindow(null, TYPE_APPLICATION); + final WindowState win1 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win1"); + final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win11"); + final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win12"); + final WindowState win2 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win2"); + final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW, mWindowToken, "win21"); + final WindowState randomWindow = + createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow"); assertTrue(win1.hasChild(win11)); assertTrue(win1.hasChild(win12)); @@ -114,34 +117,13 @@ public class WindowStateTests { } @Test - public void testGetBottomChild() throws Exception { - final WindowState parentWindow = createWindow(null, TYPE_APPLICATION); - assertNull(parentWindow.getBottomChild()); - - final WindowState child1 = createWindow(parentWindow, TYPE_APPLICATION_PANEL); - assertEquals(child1, parentWindow.getBottomChild()); - - final WindowState child2 = createWindow(parentWindow, TYPE_APPLICATION_PANEL); - // Since child1 and child2 are at the same layer, then child2 is expect to be added on top - // on child1 - assertEquals(child1, parentWindow.getBottomChild()); - - final WindowState child3 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY); - // Since child3 is a negative layer, we would expect it to be added below current children - // with positive layers. - assertEquals(child3, parentWindow.getBottomChild()); - - final WindowState child4 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY); - // We would also expect additional negative layers to be added below existing negative - // layers. - assertEquals(child4, parentWindow.getBottomChild()); - } - - @Test public void testGetParentWindow() throws Exception { - final WindowState parentWindow = createWindow(null, TYPE_APPLICATION); - final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW); - final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW); + final WindowState parentWindow = + createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow"); + final WindowState child1 = + createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1"); + final WindowState child2 = + createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2"); assertNull(parentWindow.getParentWindow()); assertEquals(parentWindow, child1.getParentWindow()); @@ -150,9 +132,9 @@ public class WindowStateTests { @Test public void testGetTopParentWindow() throws Exception { - final WindowState root = createWindow(null, TYPE_APPLICATION); - final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW); - final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW); + final WindowState root = createWindow(null, TYPE_APPLICATION, mWindowToken, "root"); + final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, mWindowToken, "child1"); + final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, mWindowToken, "child2"); assertEquals(root, root.getTopParentWindow()); assertEquals(root, child1.getTopParentWindow()); @@ -160,9 +142,12 @@ public class WindowStateTests { assertEquals(root, child2.getTopParentWindow()); } - private WindowState createWindow(WindowState parent, int type) { - final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); - - return new WindowState(sWm, null, mIWindow, mWindowToken, parent, 0, 0, attrs, 0, 0); + @Test + public void testIsOnScreen_hiddenByPolicy() { + final WindowState window = createWindow(null, TYPE_APPLICATION, mWindowToken, "window"); + window.setHasSurface(true); + assertTrue(window.isOnScreen()); + window.hideLw(false /* doAnimation */); + assertFalse(window.isOnScreen()); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java new file mode 100644 index 000000000000..9681bd2f5947 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import org.junit.Assert; +import org.junit.Before; + +import android.content.Context; +import android.os.IBinder; +import android.support.test.InstrumentationRegistry; +import android.view.Display; +import android.view.IWindow; +import android.view.WindowManager; + +import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; +import static android.app.AppOpsManager.OP_NONE; +import static android.content.res.Configuration.EMPTY; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static org.mockito.Mockito.mock; + +/** + * Common base class for window manager unit test classes. + */ +public class WindowTestsBase { + static WindowManagerService sWm = null; + private final IWindow mIWindow = new TestIWindow(); + private final Session mMockSession = mock(Session.class); + Display mDisplay; + private static int sNextStackId = FIRST_DYNAMIC_STACK_ID; + private static int sNextTaskId = 0; + + @Before + public void setUp() throws Exception { + final Context context = InstrumentationRegistry.getTargetContext(); + sWm = TestWindowManagerPolicy.getWindowManagerService(context); + mDisplay = context.getDisplay(); + } + + /** Asserts that the first entry is greater than the second entry. */ + void assertGreaterThan(int first, int second) throws Exception { + Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second); + } + + WindowToken createWindowToken(DisplayContent dc, int type) { + if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { + return new WindowToken(sWm, mock(IBinder.class), type, false, dc); + } + + final int stackId = sNextStackId++; + dc.addStackToDisplay(stackId, true); + final TaskStack stack = sWm.mStackIdToStack.get(stackId); + final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false); + stack.addTask(task, true); + final AppWindowToken token = new AppWindowToken(sWm, null, false, dc); + task.addAppToken(0, token, 0, false); + return token; + } + + WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) { + final WindowToken token = createWindowToken(dc, type); + return createWindow(parent, type, token, name); + } + + WindowState createWindow(WindowState parent, int type, WindowToken token, String name) { + final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); + attrs.setTitle(name); + + final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE, + 0, attrs, 0, 0); + // TODO: Probably better to make this call in the WindowState ctor to avoid errors with + // adding it to the token... + token.addWindow(w); + return w; + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java index 5326a192bf73..d6bfa177e440 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java @@ -39,7 +39,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; /** - * Tests for the {@link WindowState} class. + * Tests for the {@link WindowToken} class. * * Build/Install/Run: * bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests @@ -47,17 +47,7 @@ import static org.mockito.Mockito.mock; @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class WindowTokenTests { - - private WindowManagerService mWm = null; - private final IWindow mIWindow = new TestIWindow(); - private final Session mMockSession = mock(Session.class); - - @Before - public void setUp() throws Exception { - final Context context = InstrumentationRegistry.getTargetContext(); - mWm = TestWindowManagerPolicy.getWindowManagerService(context); - } +public class WindowTokenTests extends WindowTestsBase { @Test public void testAddWindow() throws Exception { @@ -65,11 +55,11 @@ public class WindowTokenTests { assertEquals(0, token.getWindowsCount()); - final WindowState window1 = createWindow(null, TYPE_APPLICATION, token); - final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window2 = createWindow(null, TYPE_APPLICATION, token); - final WindowState window3 = createWindow(null, TYPE_APPLICATION, token); + final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1"); + final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11"); + final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12"); + final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2"); + final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3"); token.addWindow(window1); // NOTE: Child windows will not be added to the token as window containers can only @@ -91,12 +81,12 @@ public class WindowTokenTests { @Test public void testChildRemoval() throws Exception { final TestWindowToken token = new TestWindowToken(); - final DisplayContent dc = mWm.getDefaultDisplayContentLocked(); + final DisplayContent dc = sWm.getDefaultDisplayContentLocked(); assertEquals(token, dc.getWindowToken(token.token)); - final WindowState window1 = createWindow(null, TYPE_APPLICATION, token); - final WindowState window2 = createWindow(null, TYPE_APPLICATION, token); + final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1"); + final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2"); token.addWindow(window1); token.addWindow(window2); @@ -113,11 +103,11 @@ public class WindowTokenTests { @Test public void testAdjustAnimLayer() throws Exception { final TestWindowToken token = new TestWindowToken(); - final WindowState window1 = createWindow(null, TYPE_APPLICATION, token); - final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window2 = createWindow(null, TYPE_APPLICATION, token); - final WindowState window3 = createWindow(null, TYPE_APPLICATION, token); + final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1"); + final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11"); + final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12"); + final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2"); + final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3"); token.addWindow(window1); token.addWindow(window2); @@ -136,60 +126,11 @@ public class WindowTokenTests { assertEquals(window3StartLayer + adj, highestLayer); } - @Test - public void testGetTopWindow() throws Exception { - final TestWindowToken token = new TestWindowToken(); - - assertNull(token.getTopWindow()); - - final WindowState window1 = createWindow(null, TYPE_APPLICATION, token); - token.addWindow(window1); - assertEquals(window1, token.getTopWindow()); - final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token); - assertEquals(window12, token.getTopWindow()); - - final WindowState window2 = createWindow(null, TYPE_APPLICATION, token); - token.addWindow(window2); - // Since new windows are added to the bottom of the token, we would still expect the - // previous one to the top. - assertEquals(window12, token.getTopWindow()); - } - - @Test - public void testGetWindowIndex() throws Exception { - final TestWindowToken token = new TestWindowToken(); - - final WindowState window1 = createWindow(null, TYPE_APPLICATION, token); - assertEquals(-1, token.getWindowIndex(window1)); - token.addWindow(window1); - assertEquals(0, token.getWindowIndex(window1)); - final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token); - final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token); - // Child windows should report the same index as their parents. - assertEquals(0, token.getWindowIndex(window11)); - assertEquals(0, token.getWindowIndex(window12)); - - final WindowState window2 = createWindow(null, TYPE_APPLICATION, token); - assertEquals(-1, token.getWindowIndex(window2)); - token.addWindow(window2); - // Since new windows are added to the bottom of the token, we would expect the added window - // to be at index 0. - assertEquals(0, token.getWindowIndex(window2)); - assertEquals(1, token.getWindowIndex(window1)); - } - - private WindowState createWindow(WindowState parent, int type, WindowToken token) { - final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); - - return new WindowState(mWm, mMockSession, mIWindow, token, parent, OP_NONE, 0, attrs, 0, 0); - } - /* Used so we can gain access to some protected members of the {@link WindowToken} class */ private class TestWindowToken extends WindowToken { TestWindowToken() { - super(mWm, mock(IBinder.class), 0, false, mWm.getDefaultDisplayContentLocked()); + super(sWm, mock(IBinder.class), 0, false, sWm.getDefaultDisplayContentLocked()); } int getWindowsCount() { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 04104b5c70d7..7217c3b973ec 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -17,7 +17,7 @@ package com.android.server.usage; import android.Manifest; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.admin.DevicePolicyManager; @@ -462,7 +462,7 @@ public class UsageStatsService extends SystemService implements final int[] runningUserIds; try { - runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds(); + runningUserIds = ActivityManager.getService().getRunningUserIds(); if (checkUserId != UserHandle.USER_ALL && !ArrayUtils.contains(runningUserIds, checkUserId)) { return false; @@ -1311,7 +1311,7 @@ public class UsageStatsService extends SystemService implements @Override public boolean isAppInactive(String packageName, int userId) { try { - userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), + userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, true, "isAppInactive", null); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); @@ -1329,7 +1329,7 @@ public class UsageStatsService extends SystemService implements public void setAppInactive(String packageName, boolean idle, int userId) { final int callingUid = Binder.getCallingUid(); try { - userId = ActivityManagerNative.getDefault().handleIncomingUser( + userId = ActivityManager.getService().handleIncomingUser( Binder.getCallingPid(), callingUid, userId, false, true, "setAppIdle", null); } catch (RemoteException re) { 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/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index a46ccee0b96d..4357dca73fbf 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -18,7 +18,6 @@ package com.android.server.voiceinteraction; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -117,7 +116,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mServiceStub = stub; mUser = userHandle; mComponent = service; - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); VoiceInteractionServiceInfo info; try { info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index 7dacf160ce4f..4267ec4ea98c 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -17,7 +17,6 @@ package com.android.server.voiceinteraction; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.assist.AssistContent; @@ -182,7 +181,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mCallback = callback; mCallingUid = callingUid; mHandler = handler; - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); mAppOps = context.getSystemService(AppOpsManager.class); diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 62625bdf953e..c99e22a42ffa 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -843,6 +843,7 @@ public final class Call { private String mParentId = null; private int mState; private List<String> mCannedTextResponses = null; + private String mCallingPackage; private String mRemainingPostDialSequence; private VideoCallImpl mVideoCallImpl; private Details mDetails; @@ -1330,19 +1331,22 @@ public final class Call { } /** {@hide} */ - Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) { + Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) { mPhone = phone; mTelecomCallId = telecomCallId; mInCallAdapter = inCallAdapter; mState = STATE_NEW; + mCallingPackage = callingPackage; } /** {@hide} */ - Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) { + Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state, + String callingPackage) { mPhone = phone; mTelecomCallId = telecomCallId; mInCallAdapter = inCallAdapter; mState = state; + mCallingPackage = callingPackage; } /** {@hide} */ @@ -1352,6 +1356,7 @@ public final class Call { /** {@hide} */ final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { + // First, we update the internal state as far as possible before firing any updates. Details details = Details.createFromParcelableCall(parcelableCall); boolean detailsChanged = !Objects.equals(mDetails, details); @@ -1367,7 +1372,7 @@ public final class Call { cannedTextResponsesChanged = true; } - VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(); + VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage); boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && !Objects.equals(mVideoCallImpl, newVideoCallImpl); if (videoCallChanged) { diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 8f9c7585ced6..2b9a50851186 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.hardware.camera2.CameraManager; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -785,7 +786,7 @@ public abstract class Connection extends Conferenceable { public static final int SESSION_EVENT_TX_STOP = 4; /** - * A camera failure has occurred for the selected camera. The {@link InCallService} can use + * A camera failure has occurred for the selected camera. The {@link VideoProvider} can use * this as a cue to inform the user the camera is not available. * @see #handleCallSessionEvent(int) */ @@ -793,13 +794,21 @@ public abstract class Connection extends Conferenceable { /** * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready - * for operation. The {@link InCallService} can use this as a cue to inform the user that + * for operation. The {@link VideoProvider} can use this as a cue to inform the user that * the camera has become available again. * @see #handleCallSessionEvent(int) */ public static final int SESSION_EVENT_CAMERA_READY = 6; /** + * Session event raised by Telecom when + * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the + * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission. + * @see #handleCallSessionEvent(int) + */ + public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; + + /** * Session modify request was successful. * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) */ @@ -848,6 +857,8 @@ public abstract class Connection extends Conferenceable { private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP"; private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL"; private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY"; + private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR = + "CAMERA_PERMISSION_ERROR"; private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN"; private VideoProvider.VideoProviderHandler mMessageHandler; @@ -906,8 +917,17 @@ public abstract class Connection extends Conferenceable { break; } case MSG_SET_CAMERA: - onSetCamera((String) msg.obj); - break; + { + SomeArgs args = (SomeArgs) msg.obj; + try { + onSetCamera((String) args.arg1); + onSetCamera((String) args.arg1, (String) args.arg2, args.argi1, + args.argi2); + } finally { + args.recycle(); + } + } + break; case MSG_SET_PREVIEW_SURFACE: onSetPreviewSurface((Surface) msg.obj); break; @@ -962,8 +982,19 @@ public abstract class Connection extends Conferenceable { MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); } - public void setCamera(String cameraId) { - mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); + public void setCamera(String cameraId, String callingPackageName) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = cameraId; + // Propagate the calling package; originally determined in + // android.telecom.InCallService.VideoCall#setCamera(String) from the calling + // process. + args.arg2 = callingPackageName; + // Pass along the uid and pid of the calling app; this gets lost when we put the + // message onto the handler. These are required for Telecom to perform a permission + // check to see if the calling app is able to use the camera. + args.argi1 = Binder.getCallingUid(); + args.argi2 = Binder.getCallingPid(); + mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget(); } public void setPreviewSurface(Surface surface) { @@ -1048,6 +1079,29 @@ public abstract class Connection extends Conferenceable { public abstract void onSetCamera(String cameraId); /** + * Sets the camera to be used for the outgoing video. + * <p> + * The {@link VideoProvider} should respond by communicating the capabilities of the chosen + * camera via + * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. + * <p> + * This prototype is used internally to ensure that the calling package name, UID and PID + * are sent to Telecom so that can perform a camera permission check on the caller. + * <p> + * Sent from the {@link InCallService} via + * {@link InCallService.VideoCall#setCamera(String)}. + * + * @param cameraId The id of the camera (use ids as reported by + * {@link CameraManager#getCameraIdList()}). + * @param callingPackageName The AppOpps package name of the caller. + * @param callingUid The UID of the caller. + * @param callingPid The PID of the caller. + * @hide + */ + public void onSetCamera(String cameraId, String callingPackageName, int callingUid, + int callingPid) {} + + /** * Sets the surface to be used for displaying a preview of what the user's camera is * currently capturing. When video transmission is enabled, this is the video signal which * is sent to the remote device. @@ -1233,7 +1287,8 @@ public abstract class Connection extends Conferenceable { * {@link VideoProvider#SESSION_EVENT_TX_START}, * {@link VideoProvider#SESSION_EVENT_TX_STOP}, * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, - * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}. + * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}, + * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}. */ public void handleCallSessionEvent(int event) { if (mVideoCallbacks != null) { @@ -1382,6 +1437,8 @@ public abstract class Connection extends Conferenceable { return SESSION_EVENT_TX_START_STR; case SESSION_EVENT_TX_STOP: return SESSION_EVENT_TX_STOP_STR; + case SESSION_EVENT_CAMERA_PERMISSION_ERROR: + return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR; default: return SESSION_EVENT_UNKNOWN_STR + " " + event; } 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/InCallService.java b/telecomm/java/android/telecom/InCallService.java index 69de89d5ed74..5d68aaeda988 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -87,7 +87,8 @@ public abstract class InCallService extends Service { switch (msg.what) { case MSG_SET_IN_CALL_ADAPTER: - mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj)); + String callingPackage = getApplicationContext().getOpPackageName(); + mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage); mPhone.addListener(mPhoneListener); onPhoneCreated(mPhone); break; @@ -664,7 +665,8 @@ public abstract class InCallService extends Service { * {@link Connection.VideoProvider#SESSION_EVENT_TX_START}, * {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP}, * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, - * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}. + * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}, + * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}. */ public abstract void onCallSessionEvent(int event); 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/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index 4a6fd7c16c1a..1900cb9857d9 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -182,10 +182,10 @@ public final class ParcelableCall implements Parcelable { * @return The video call. */ - public VideoCallImpl getVideoCallImpl() { + public VideoCallImpl getVideoCallImpl(String callingPackageName) { if (mVideoCall == null && mVideoCallProvider != null) { try { - mVideoCall = new VideoCallImpl(mVideoCallProvider); + mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName); } catch (RemoteException ignored) { // Ignore RemoteException. } diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index a4ef5601e551..30ec5b350307 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -125,13 +125,16 @@ public final class Phone { private boolean mCanAddCall = true; - Phone(InCallAdapter adapter) { + private final String mCallingPackage; + + Phone(InCallAdapter adapter, String callingPackage) { mInCallAdapter = adapter; + mCallingPackage = callingPackage; } final void internalAddCall(ParcelableCall parcelableCall) { Call call = new Call(this, parcelableCall.getId(), mInCallAdapter, - parcelableCall.getState()); + parcelableCall.getState(), mCallingPackage); mCallByTelecomCallId.put(parcelableCall.getId(), call); mCalls.add(call); checkCallTree(parcelableCall); diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index 473e39457f58..0457d6372d8b 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -114,7 +114,10 @@ public final class PhoneAccount implements Parcelable { public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4; /** - * Flag indicating that this {@code PhoneAccount} is capable of placing video calls. + * Flag indicating that this {@code PhoneAccount} is currently able to place video calls. + * <p> + * See also {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING} which indicates whether the + * {@code PhoneAccount} supports placing video calls. * <p> * See {@link #getCapabilities} */ @@ -179,6 +182,23 @@ public final class PhoneAccount implements Parcelable { public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200; /** + * Flag indicating that this {@link PhoneAccount} supports video calling. + * This is not an indication that the {@link PhoneAccount} is currently able to make a video + * call, but rather that it has the ability to make video calls (but not necessarily at this + * time). + * <p> + * Whether a {@link PhoneAccount} can make a video call is ultimately controlled by + * {@link #CAPABILITY_VIDEO_CALLING}, which indicates whether the {@link PhoneAccount} is + * currently capable of making a video call. Consider a case where, for example, a + * {@link PhoneAccount} supports making video calls (e.g. + * {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING}), but a current lack of network connectivity + * prevents video calls from being made (e.g. {@link #CAPABILITY_VIDEO_CALLING}). + * <p> + * See {@link #getCapabilities} + */ + public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 0x400; + + /** * URI scheme for telephone number URIs. */ public static final String SCHEME_TEL = "tel"; @@ -762,6 +782,9 @@ public final class PhoneAccount implements Parcelable { */ private String capabilitiesToString(int capabilities) { StringBuilder sb = new StringBuilder(); + if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) { + sb.append("SuppVideo "); + } if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) { sb.append("Video "); } diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java index 0e4f53e4881a..77e0e5486127 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -408,6 +408,8 @@ public final class RemoteConnection { private final IVideoProvider mVideoProviderBinder; + private final String mCallingPackage; + /** * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is * load factor before resizing, 1 means we only expect a single thread to @@ -416,8 +418,9 @@ public final class RemoteConnection { private final Set<Callback> mCallbacks = Collections.newSetFromMap( new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1)); - VideoProvider(IVideoProvider videoProviderBinder) { + VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) { mVideoProviderBinder = videoProviderBinder; + mCallingPackage = callingPackage; try { mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder()); } catch (RemoteException e) { @@ -452,7 +455,7 @@ public final class RemoteConnection { */ public void setCamera(String cameraId) { try { - mVideoProviderBinder.setCamera(cameraId); + mVideoProviderBinder.setCamera(cameraId, mCallingPackage); } catch (RemoteException e) { } } @@ -628,7 +631,7 @@ public final class RemoteConnection { * @hide */ RemoteConnection(String callId, IConnectionService connectionService, - ParcelableConnection connection) { + ParcelableConnection connection, String callingPackage) { mConnectionId = callId; mConnectionService = connectionService; mConnected = true; @@ -640,7 +643,7 @@ public final class RemoteConnection { mVideoState = connection.getVideoState(); IVideoProvider videoProvider = connection.getVideoProvider(); if (videoProvider != null) { - mVideoProvider = new RemoteConnection.VideoProvider(videoProvider); + mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage); } else { mVideoProvider = null; } diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index 0a8470af7a7d..d8a226a3b529 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -283,9 +283,13 @@ final class RemoteConnectionService { @Override public void setVideoProvider(String callId, IVideoProvider videoProvider, Session.Info sessionInfo) { + + String callingPackage = mOurConnectionServiceImpl.getApplicationContext() + .getOpPackageName(); RemoteConnection.VideoProvider remoteVideoProvider = null; if (videoProvider != null) { - remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider); + remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider, + callingPackage); } findConnectionForAction(callId, "setVideoProvider") .setVideoProvider(remoteVideoProvider); @@ -351,8 +355,10 @@ final class RemoteConnectionService { @Override public void addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo) { + String callingPackage = mOurConnectionServiceImpl.getApplicationContext(). + getOpPackageName(); RemoteConnection remoteConnection = new RemoteConnection(callId, - mOutgoingConnectionServiceRpc, connection); + mOutgoingConnectionServiceRpc, connection, callingPackage); mConnectionById.put(callId, remoteConnection); remoteConnection.registerCallback(new RemoteConnection.Callback() { @Override diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index e54abeebb880..d8ede5c21316 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -43,6 +43,7 @@ public class VideoCallImpl extends VideoCall { private VideoCall.Callback mCallback; private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN; private int mVideoState = VideoProfile.STATE_AUDIO_ONLY; + private final String mCallingPackageName; private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override @@ -197,12 +198,13 @@ public class VideoCallImpl extends VideoCall { private Handler mHandler; - VideoCallImpl(IVideoProvider videoProvider) throws RemoteException { + VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException { mVideoProvider = videoProvider; mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); mBinder = new VideoCallListenerBinder(); mVideoProvider.addVideoCallback(mBinder); + mCallingPackageName = callingPackageName; } public void destroy() { @@ -240,7 +242,8 @@ public class VideoCallImpl extends VideoCall { /** {@inheritDoc} */ public void setCamera(String cameraId) { try { - mVideoProvider.setCamera(cameraId); + Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName); + mVideoProvider.setCamera(cameraId, mCallingPackageName); } catch (RemoteException e) { } } diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl index 68e5fd48e1ac..a109e90243fe 100644 --- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl +++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl @@ -30,7 +30,7 @@ oneway interface IVideoProvider { void removeVideoCallback(IBinder videoCallbackBinder); - void setCamera(String cameraId); + void setCamera(String cameraId, in String mCallingPackageName); void setPreviewSurface(in Surface surface); 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/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 3c0a8d6f8a38..434caadeedc6 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -168,20 +168,34 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P } /** - * @hide + * Get reference signal received quality */ public int getRsrq() { return mRsrq; } /** - * @hide + * Get reference signal signal-to-noise ratio */ public int getRssnr() { return mRssnr; } /** + * Get reference signal received power + */ + public int getRsrp() { + return mRsrp; + } + + /** + * Get channel quality indicator + */ + public int getCqi() { + return mCqi; + } + + /** * Get signal strength as dBm */ @Override diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index bb2b4478433d..32f487bb5dbe 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -233,7 +233,7 @@ public class PhoneStateListener { * @hide */ /** @hide */ - protected int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + protected Integer mSubId; private final Handler mHandler; @@ -242,7 +242,7 @@ public class PhoneStateListener { * This class requires Looper.myLooper() not return null. */ public PhoneStateListener() { - this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, Looper.myLooper()); + this(null, Looper.myLooper()); } /** @@ -251,7 +251,7 @@ public class PhoneStateListener { * @hide */ public PhoneStateListener(Looper looper) { - this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, looper); + this(null, looper); } /** @@ -260,7 +260,7 @@ public class PhoneStateListener { * own non-null Looper use PhoneStateListener(int subId, Looper looper) below. * @hide */ - public PhoneStateListener(int subId) { + public PhoneStateListener(Integer subId) { this(subId, Looper.myLooper()); } @@ -269,7 +269,7 @@ public class PhoneStateListener { * and non-null Looper. * @hide */ - public PhoneStateListener(int subId, Looper looper) { + public PhoneStateListener(Integer subId, Looper looper) { if (DBG) log("ctor: subId=" + subId + " looper=" + looper); mSubId = subId; mHandler = new Handler(looper) { 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/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d75dd7d1f6f1..ad97a8ff2a88 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -263,6 +263,22 @@ public class TelephonyManager { return new TelephonyManager(mContext, subId); } + /** + * Create a new TelephonyManager object pinned to the subscription ID associated with the given + * phone account. + * + * @return a TelephonyManager that uses the given phone account for all calls, or {@code null} + * if the phone account does not correspond to a valid subscription ID. + */ + @Nullable + public TelephonyManager createForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) { + int subId = getSubIdForPhoneAccountHandle(phoneAccountHandle); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return null; + } + return new TelephonyManager(mContext, subId); + } + /** {@hide} */ public boolean isMultiSimEnabled() { return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") || @@ -670,42 +686,49 @@ public class TelephonyManager { public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY; /** - * Broadcast intent action for letting custom component know to show voicemail notification. - * @hide + * Broadcast intent action for letting the default dialer to know to show voicemail + * notification. + * + * <p> + * The {@link #EXTRA_NOTIFICATION_COUNT} extra indicates the total numbers of unheard + * voicemails. + * The {@link #EXTRA_VOICEMAIL_NUMBER} extra indicates the voicemail number if available. + * The {@link #EXTRA_CALL_VOICEMAIL_INTENT} extra is a {@link android.app.PendingIntent} that + * will call the voicemail number when sent. This extra will be empty if the voicemail number + * is not set, and {@link #EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT} will be set instead. + * The {@link #EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT} extra is a + * {@link android.app.PendingIntent} that will launch the voicemail settings. This extra is only + * available when the voicemail number is not set. + * + * @see #EXTRA_NOTIFICATION_COUNT + * @see #EXTRA_VOICEMAIL_NUMBER + * @see #EXTRA_CALL_VOICEMAIL_INTENT + * @see #EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT */ - @SystemApi public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; /** * The number of voice messages associated with the notification. - * @hide */ - @SystemApi public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT"; /** * The voicemail number. - * @hide */ - @SystemApi public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER"; /** * The intent to call voicemail. - * @hide */ - @SystemApi public static final String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT"; /** * The intent to launch voicemail settings. - * @hide */ - @SystemApi public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT"; @@ -3019,6 +3042,12 @@ public class TelephonyManager { if (mContext == null) return; try { Boolean notifyNow = (getITelephony() != null); + // If the listener has not explicitly set the subId (for example, created with the + // default constructor), replace the subId so it will listen to the account the + // telephony manager is created with. + if (listener.mSubId == null) { + listener.mSubId = mSubId; + } sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(), listener.callback, events, notifyNow); } catch (RemoteException ex) { @@ -4650,32 +4679,46 @@ public class TelephonyManager { /* <p>Requires permission: * @link android.Manifest.permission#CALL_PHONE} + * @param ussdRequest the USSD command to be executed. + * @param wrappedCallback receives a callback result. */ @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String ussdRequest, final OnReceiveUssdResponseCallback callback, Handler handler) { - checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null."); - - ResultReceiver wrappedCallback = new ResultReceiver(handler) { - @Override - protected void onReceiveResult(int resultCode, Bundle ussdResponse) { - Rlog.d(TAG, "USSD:" + resultCode); - checkNotNull(ussdResponse, "ussdResponse cannot be null."); - UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE); - - if (resultCode == USSD_RETURN_SUCCESS) { - callback.onReceiveUssdResponse(response.getUssdRequest(), - response.getReturnMessage()); - } else { - callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode); - } - } + sendUssdRequest(ussdRequest, getSubId(), callback, handler); + } + + /* <p>Requires permission: + * @link android.Manifest.permission#CALL_PHONE} + * @param subId The subscription to use. + * @param ussdRequest the USSD command to be executed. + * @param wrappedCallback receives a callback result. + */ + @RequiresPermission(android.Manifest.permission.CALL_PHONE) + public void sendUssdRequest(String ussdRequest, int subId, + final OnReceiveUssdResponseCallback callback, Handler handler) { + checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null."); + + ResultReceiver wrappedCallback = new ResultReceiver(handler) { + @Override + protected void onReceiveResult(int resultCode, Bundle ussdResponse) { + Rlog.d(TAG, "USSD:" + resultCode); + checkNotNull(ussdResponse, "ussdResponse cannot be null."); + UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE); + + if (resultCode == USSD_RETURN_SUCCESS) { + callback.onReceiveUssdResponse(response.getUssdRequest(), + response.getReturnMessage()); + } else { + callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode); + } + } }; try { ITelephony telephony = getITelephony(); if (telephony != null) { - telephony.handleUssdRequest(ussdRequest, wrappedCallback); + telephony.handleUssdRequest(subId, ussdRequest, wrappedCallback); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#sendUSSDCode", e); @@ -5432,6 +5475,19 @@ public class TelephonyManager { return retval; } + private int getSubIdForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) { + int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + try { + ITelecomService service = getTelecomService(); + if (service != null) { + retval = getSubIdForPhoneAccount(service.getPhoneAccount(phoneAccountHandle)); + } + } catch (RemoteException e) { + } + + return retval; + } + /** * Resets telephony manager settings back to factory defaults. * @@ -5481,6 +5537,16 @@ public class TelephonyManager { } /** + * Returns the current {@link ServiceState} information. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + */ + public ServiceState getServiceState() { + return getServiceStateForSubscriber(getSubId()); + } + + /** * Returns the service state information on specified subscription. Callers require * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information. * @hide diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl index 5b7114982758..2ae424f4af8e 100644 --- a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl +++ b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl @@ -89,4 +89,11 @@ interface IPresenceListener */ void listCapInfoReceived(in PresRlmiInfo rlmiInfo, in PresResInfo [] resInfo); + + /** + * Callback function to be invoked to inform the client when Unpublish message + * is sent to network. + */ + void unpublishMessageSent(); + }
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 4c66be1955df..9c62988c0e25 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -275,10 +275,11 @@ interface ITelephony { /** * Handles USSD commands. * + * @param subId The subscription to use. * @param ussdRequest the USSD command to be executed. * @param wrappedCallback receives a callback result. */ - void handleUssdRequest(String ussdRequest, in ResultReceiver wrappedCallback); + void handleUssdRequest(int subId, String ussdRequest, in ResultReceiver wrappedCallback); /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java index 5ef71df341bf..e443911b2de0 100644 --- a/test-runner/src/android/test/mock/MockContentProvider.java +++ b/test-runner/src/android/test/mock/MockContentProvider.java @@ -147,6 +147,12 @@ public class MockContentProvider extends ContentProvider { public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException { return MockContentProvider.this.uncanonicalize(uri); } + + @Override + public boolean refresh(String callingPkg, Uri url, Bundle args, + ICancellationSignal cancellationSignal) throws RemoteException { + return MockContentProvider.this.refresh(url, args); + } } private final InversionIContentProvider mIContentProvider = new InversionIContentProvider(); @@ -251,6 +257,13 @@ public class MockContentProvider extends ContentProvider { } /** + * @hide + */ + public boolean refresh(Uri url, Bundle args) { + throw new UnsupportedOperationException("unimplemented mock method call"); + } + + /** * Returns IContentProvider which calls back same methods in this class. * By overriding this class, we avoid the mechanism hidden behind ContentProvider * (IPC, etc.) diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index fdd971b1fc00..190fc35e4873 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -17,6 +17,8 @@ package android.test.mock; import android.annotation.SystemApi; +import android.app.IApplicationThread; +import android.app.IServiceConnection; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -759,4 +761,23 @@ public class MockContext extends Context { public boolean isCredentialProtectedStorage() { throw new UnsupportedOperationException(); } + + /** {@hide} */ + @Override + public IBinder getActivityToken() { + throw new UnsupportedOperationException(); + } + + /** {@hide} */ + @Override + public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler, + int flags) { + throw new UnsupportedOperationException(); + } + + /** {@hide} */ + @Override + public IApplicationThread getIApplicationThread() { + throw new UnsupportedOperationException(); + } } diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java index ee8c376b0110..09d45d100c2b 100644 --- a/test-runner/src/android/test/mock/MockIContentProvider.java +++ b/test-runner/src/android/test/mock/MockIContentProvider.java @@ -125,4 +125,10 @@ public class MockIContentProvider implements IContentProvider { public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException { throw new UnsupportedOperationException("unimplemented mock method"); } + + @Override + public boolean refresh(String callingPkg, Uri url, Bundle args, + ICancellationSignal cancellationSignal) throws RemoteException { + throw new UnsupportedOperationException("unimplemented mock method"); + } } 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/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index f5f7ea3895d7..0aa20ef85e8a 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -19,7 +19,6 @@ import java.io.OutputStreamWriter; import android.accounts.Account; import android.accounts.AccountManager; -import android.app.ActivityManagerNative; import android.app.ActivityManager; import android.app.ActivityManager.ProcessErrorStateInfo; import android.content.Context; @@ -144,7 +143,7 @@ public class AppLaunch extends InstrumentationTestCase { InstrumentationTestRunner instrumentation = (InstrumentationTestRunner)getInstrumentation(); Bundle args = instrumentation.getArguments(); - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY); mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY); mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE)); diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java index b65913515ced..7a4fddf7312b 100644 --- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java +++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java @@ -17,7 +17,6 @@ package com.android.imftest.samples; import android.app.Activity; -import android.app.ActivityManagerNative; import android.os.Bundle; import android.os.RemoteException; import android.provider.MediaStore; diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java index a7e3bece6e63..1ae318a96a50 100644 --- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java +++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java @@ -18,7 +18,6 @@ package com.android.tests.memoryusage; import android.app.ActivityManager; import android.app.ActivityManager.ProcessErrorStateInfo; import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.UiAutomation; import android.content.Context; @@ -84,7 +83,7 @@ public class MemoryUsageTest extends InstrumentationTestCase { MemoryUsageInstrumentation instrumentation = (MemoryUsageInstrumentation) getInstrumentation(); Bundle args = instrumentation.getBundle(); - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); createMappings(); parseArgs(args); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 4a6fb13d2073..34acebfef52b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -728,10 +728,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { static private void waitFor(Criteria criteria) { int delays = 0; while (!criteria.get()) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - } + sleepFor(50); if (++delays == 10) fail(); } } @@ -2313,10 +2310,30 @@ public class ConnectivityServiceTest extends AndroidTestCase { networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); // pass timeout and validate that UNAVAILABLE is not called - try { - Thread.sleep(15); - } catch (InterruptedException e) { - } + sleepFor(15); + networkCallback.assertNoCallback(); + } + + /** + * Validate that a satisfied network request followed by a disconnected (lost) network does + * not trigger onUnavailable() once the time-out period expires. + */ + @SmallTest + public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() { + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI).build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + mCm.requestNetwork(nr, networkCallback, 500); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); + sleepFor(20); + mWiFiNetworkAgent.disconnect(); + networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + + // pass timeout and validate that UNAVAILABLE is not called + sleepFor(600); networkCallback.assertNoCallback(); } @@ -2358,10 +2375,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // pass timeout and validate that no callbacks // Note: doesn't validate that nothing called from CS since even if called the CM already // unregisters the callback and won't pass it through! - try { - Thread.sleep(15); - } catch (InterruptedException e) { - } + sleepFor(15); networkCallback.assertNoCallback(); // create a network satisfying request - validate that request not triggered @@ -2775,4 +2789,13 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(pendingIntent); } } + + /* test utilities */ + static private void sleepFor(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + } + + } } diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index 6ff0c5a8595e..6a064d271bcc 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java @@ -25,7 +25,7 @@ import static com.android.server.connectivity.MetricsTestUtil.anInt; import static com.android.server.connectivity.MetricsTestUtil.anIntArray; import static com.android.server.connectivity.MetricsTestUtil.b; import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent; -import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog; +import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog; import android.net.ConnectivityMetricsEvent; import android.net.metrics.ApfProgramEvent; diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index c7982b1a1f39..78d16d93287e 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -34,7 +34,7 @@ import android.net.metrics.ValidationProbeEvent; import android.os.Parcelable; import android.util.Base64; -import com.android.server.connectivity.metrics.IpConnectivityLogClass; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass; import junit.framework.TestCase; diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java index a30b3629d5c4..9f7261dc6019 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java @@ -59,13 +59,14 @@ public class TetherInterfaceStateMachineTest { @Mock private INetworkStatsService mStatsService; @Mock private IControlsTethering mTetherHelper; @Mock private InterfaceConfiguration mInterfaceConfiguration; + @Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices; private final TestLooper mLooper = new TestLooper(); private TetherInterfaceStateMachine mTestedSm; private void initStateMachine(int interfaceType) throws Exception { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType, - mNMService, mStatsService, mTetherHelper); + mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices); mTestedSm.start(); // Starting the state machine always puts us in a consistent state and notifies // the test of the world that we've changed from an unknown to available state. @@ -91,7 +92,8 @@ public class TetherInterfaceStateMachineTest { @Test public void startsOutAvailable() { mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), - ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper); + ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper, + mIPv6TetheringInterfaceServices); mTestedSm.start(); mLooper.dispatchAll(); verify(mTetherHelper).notifyInterfaceStateChange( @@ -274,4 +276,4 @@ public class TetherInterfaceStateMachineTest { upstreamIface); mLooper.dispatchAll(); } -}
\ No newline at end of file +} diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java index d7f4a38f7644..89bd8d8f1dd4 100644 --- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java @@ -16,7 +16,7 @@ package com.android.framework.permission.tests; -import android.app.ActivityManagerNative; +import android.app.ActivityManager; import android.app.IActivityManager; import android.content.res.Configuration; import android.os.RemoteException; @@ -33,7 +33,7 @@ public class ActivityManagerPermissionTests extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); - mAm = ActivityManagerNative.getDefault(); + mAm = ActivityManager.getService(); } @SmallTest diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 8dd176d27345..a3404e5db21c 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -25,7 +25,7 @@ namespace aapt { static const char* sMajorVersion = "2"; // Update minor version whenever a feature or flag is added. -static const char* sMinorVersion = "2"; +static const char* sMinorVersion = "3"; int PrintVersion() { std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "." diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp index 1d414743de71..3eef7aa71a92 100644 --- a/tools/aapt2/Resource.cpp +++ b/tools/aapt2/Resource.cpp @@ -41,6 +41,8 @@ StringPiece ToString(ResourceType type) { return "dimen"; case ResourceType::kDrawable: return "drawable"; + case ResourceType::kFont: + return "font"; case ResourceType::kFraction: return "fraction"; case ResourceType::kId: @@ -83,6 +85,7 @@ static const std::map<StringPiece, ResourceType> sResourceTypeMap{ {"color", ResourceType::kColor}, {"dimen", ResourceType::kDimen}, {"drawable", ResourceType::kDrawable}, + {"font", ResourceType::kFont}, {"fraction", ResourceType::kFraction}, {"id", ResourceType::kId}, {"integer", ResourceType::kInteger}, diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index 78acb700c7c0..13330b548d2c 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -46,6 +46,7 @@ enum class ResourceType { kColor, kDimen, kDrawable, + kFont, kFraction, kId, kInteger, diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp index 720ab91c5740..6acb4d3eb850 100644 --- a/tools/aapt2/Resource_test.cpp +++ b/tools/aapt2/Resource_test.cpp @@ -57,6 +57,10 @@ TEST(ResourceTypeTest, ParseResourceTypes) { ASSERT_NE(type, nullptr); EXPECT_EQ(*type, ResourceType::kDrawable); + type = ParseResourceType("font"); + ASSERT_NE(type, nullptr); + EXPECT_EQ(*type, ResourceType::kFont); + type = ParseResourceType("fraction"); ASSERT_NE(type, nullptr); EXPECT_EQ(*type, ResourceType::kFraction); diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp index a06140cff542..f0b18e65cc1a 100644 --- a/tools/aapt2/compile/Compile.cpp +++ b/tools/aapt2/compile/Compile.cpp @@ -482,7 +482,9 @@ class BigBufferOutputStream : public io::OutputStream { void BackUp(int count) override { buffer_->BackUp(count); } - int64_t ByteCount() const override { return buffer_->size(); } + google::protobuf::int64 ByteCount() const override { + return buffer_->size(); + } bool HadError() const override { return false; } diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp index f1bc53ee9cf7..7ab05b58b8b9 100644 --- a/tools/aapt2/compile/Png.cpp +++ b/tools/aapt2/compile/Png.cpp @@ -232,6 +232,13 @@ PNG_COLOR_TYPE_RGB_ALPHA) { } }*/ +#ifdef MAX +#undef MAX +#endif +#ifdef ABS +#undef ABS +#endif + #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define ABS(a) ((a) < 0 ? -(a) : (a)) diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h index 01c9adbc9094..aff1da3f05d2 100644 --- a/tools/aapt2/compile/Png.h +++ b/tools/aapt2/compile/Png.h @@ -62,8 +62,8 @@ class PngChunkFilter : public io::InputStream { void BackUp(int count) override; bool Skip(int count) override; - int64_t ByteCount() const override { - return static_cast<int64_t>(window_start_); + google::protobuf::int64 ByteCount() const override { + return static_cast<google::protobuf::int64>(window_start_); } bool HadError() const override { return error_; } diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf b/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf b/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml b/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml new file mode 100644 index 000000000000..1fb67914894e --- /dev/null +++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<font-family xmlns:android="http://schemas.android.com/apk/res/android"> + <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/myfont-normal" /> + <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/myfont-italic" /> +</font-family> diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp index 68db6b333bdc..0d0e46da4ec8 100644 --- a/tools/aapt2/proto/TableProtoSerializer.cpp +++ b/tools/aapt2/proto/TableProtoSerializer.cpp @@ -361,7 +361,7 @@ bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) { bool CompiledFileInputStream::ReadCompiledFile(pb::CompiledFile* out_val) { EnsureAlignedRead(); - uint64_t pb_size = 0u; + google::protobuf::uint64 pb_size = 0u; if (!in_.ReadLittleEndian64(&pb_size)) { return false; } @@ -389,7 +389,7 @@ bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) { EnsureAlignedRead(); - uint64_t pb_size = 0u; + google::protobuf::uint64 pb_size = 0u; if (!in_.ReadLittleEndian64(&pb_size)) { return false; } diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md index 93c790d80c4c..ac411b15ae83 100644 --- a/tools/aapt2/readme.md +++ b/tools/aapt2/readme.md @@ -1,5 +1,9 @@ # Android Asset Packaging Tool 2.0 (AAPT2) release notes +## Version 2.3 +### `aapt2` +- Support new `font` resource type. + ## Version 2.2 ### `aapt2 compile ...` - Added support for inline complex XML resources. See diff --git a/tools/layoutlib/.gitignore b/tools/layoutlib/.gitignore index eb52b64fd32c..819103db9d99 100644 --- a/tools/layoutlib/.gitignore +++ b/tools/layoutlib/.gitignore @@ -1,3 +1,4 @@ bin /.idea/workspace.xml /out +/bridge/out diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml index 57d08cb22c7e..fbaed520fff9 100644 --- a/tools/layoutlib/bridge/bridge.iml +++ b/tools/layoutlib/bridge/bridge.iml @@ -7,6 +7,7 @@ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/tests/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/tests/src" isTestSource="true" /> + <sourceFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/src/main/myapplication.widgets" isTestSource="true" /> <excludeFolder url="file://$MODULE_DIR$/.settings" /> <excludeFolder url="file://$MODULE_DIR$/bin" /> <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/.gradle" /> diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index e1fc5ec2944c..2ae46540674f 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -326,7 +326,7 @@ public final class Bitmap_Delegate { @LayoutlibDelegate /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height, - int config, int allocSize, boolean isPremultiplied) { + int config, boolean isPremultiplied) { Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Bitmap.reconfigure() is not supported", null /*data*/); } @@ -600,6 +600,22 @@ public final class Bitmap_Delegate { return Arrays.equals(argb1, argb2); } + @LayoutlibDelegate + /*package*/ static int nativeGetAllocationByteCount(long nativeBitmap) { + // get the delegate from the native int. + Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); + if (delegate == null) { + return 0; + } + return nativeRowBytes(nativeBitmap) * delegate.mImage.getHeight(); + + } + + @LayoutlibDelegate + /*package*/ static void nativePrepareToDraw(long nativeBitmap) { + // do nothing as Bitmap_Delegate does not have caches + } + // ---- Private delegate/helper methods ---- private Bitmap_Delegate(BufferedImage image, Config config) { diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 4a4c6c81a77f..94152cd73ca2 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -110,17 +110,17 @@ public final class Canvas_Delegate { // ---- native methods ---- @LayoutlibDelegate - /*package*/ static void freeCaches() { + /*package*/ static void nFreeCaches() { // nothing to be done here. } @LayoutlibDelegate - /*package*/ static void freeTextLayoutCaches() { + /*package*/ static void nFreeTextLayoutCaches() { // nothing to be done here yet. } @LayoutlibDelegate - /*package*/ static long initRaster(@Nullable Bitmap bitmap) { + /*package*/ static long nInitRaster(@Nullable Bitmap bitmap) { long nativeBitmapOrZero = 0; if (bitmap != null) { nativeBitmapOrZero = bitmap.getNativeInstance(); @@ -142,7 +142,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_setBitmap(long canvas, Bitmap bitmap) { + public static void nSetBitmap(long canvas, Bitmap bitmap) { Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); if (canvasDelegate == null || bitmapDelegate==null) { @@ -153,7 +153,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static boolean native_isOpaque(long nativeCanvas) { + public static boolean nIsOpaque(long nativeCanvas) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -164,10 +164,10 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){} + public static void nSetHighContrastText(long nativeCanvas, boolean highContrastText){} @LayoutlibDelegate - public static int native_getWidth(long nativeCanvas) { + public static int nGetWidth(long nativeCanvas) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -178,7 +178,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static int native_getHeight(long nativeCanvas) { + public static int nGetHeight(long nativeCanvas) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -189,7 +189,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static int native_save(long nativeCanvas, int saveFlags) { + public static int nSave(long nativeCanvas, int saveFlags) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -200,7 +200,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static int native_saveLayer(long nativeCanvas, float l, + public static int nSaveLayer(long nativeCanvas, float l, float t, float r, float b, long paint, int layerFlags) { // get the delegate from the native int. @@ -219,7 +219,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static int native_saveLayerAlpha(long nativeCanvas, float l, + public static int nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, int alpha, int layerFlags) { // get the delegate from the native int. @@ -232,7 +232,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_restore(long nativeCanvas, boolean throwOnUnderflow) { + public static void nRestore(long nativeCanvas, boolean throwOnUnderflow) { // FIXME: implement throwOnUnderflow. // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); @@ -244,7 +244,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_restoreToCount(long nativeCanvas, int saveCount, + public static void nRestoreToCount(long nativeCanvas, int saveCount, boolean throwOnUnderflow) { // FIXME: implement throwOnUnderflow. // get the delegate from the native int. @@ -257,7 +257,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static int native_getSaveCount(long nativeCanvas) { + public static int nGetSaveCount(long nativeCanvas) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -268,7 +268,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_translate(long nativeCanvas, float dx, float dy) { + public static void nTranslate(long nativeCanvas, float dx, float dy) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -279,7 +279,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_scale(long nativeCanvas, float sx, float sy) { + public static void nScale(long nativeCanvas, float sx, float sy) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -290,7 +290,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_rotate(long nativeCanvas, float degrees) { + public static void nRotate(long nativeCanvas, float degrees) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -301,7 +301,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_skew(long nativeCanvas, float kx, float ky) { + public static void nSkew(long nativeCanvas, float kx, float ky) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -325,7 +325,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_concat(long nCanvas, long nMatrix) { + public static void nConcat(long nCanvas, long nMatrix) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); if (canvasDelegate == null) { @@ -353,7 +353,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_setMatrix(long nCanvas, long nMatrix) { + public static void nSetMatrix(long nCanvas, long nMatrix) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); if (canvasDelegate == null) { @@ -383,7 +383,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static boolean native_clipRect(long nCanvas, + public static boolean nClipRect(long nCanvas, float left, float top, float right, float bottom, int regionOp) { @@ -397,7 +397,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static boolean native_clipPath(long nativeCanvas, + public static boolean nClipPath(long nativeCanvas, long nativePath, int regionOp) { Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); @@ -414,7 +414,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static boolean native_clipRegion(long nativeCanvas, + public static boolean nClipRegion(long nativeCanvas, long nativeRegion, int regionOp) { Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); @@ -431,7 +431,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) { + public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) { Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; @@ -446,7 +446,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static boolean native_getClipBounds(long nativeCanvas, + public static boolean nGetClipBounds(long nativeCanvas, Rect bounds) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); @@ -467,7 +467,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_getCTM(long canvas, long matrix) { + public static void nGetCTM(long canvas, long matrix) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); if (canvasDelegate == null) { @@ -484,13 +484,13 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static boolean native_quickReject(long nativeCanvas, long path) { + public static boolean nQuickReject(long nativeCanvas, long path) { // FIXME properly implement quickReject return false; } @LayoutlibDelegate - public static boolean native_quickReject(long nativeCanvas, + public static boolean nQuickReject(long nativeCanvas, float left, float top, float right, float bottom) { // FIXME properly implement quickReject @@ -498,7 +498,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawColor(long nativeCanvas, final int color, final int mode) { + public static void nDrawColor(long nativeCanvas, final int color, final int mode) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { @@ -529,14 +529,14 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawPaint(long nativeCanvas, long paint) { + public static void nDrawPaint(long nativeCanvas, long paint) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "Canvas.drawPaint is not supported.", null, null /*data*/); } @LayoutlibDelegate - public static void native_drawPoint(long nativeCanvas, float x, float y, + public static void nDrawPoint(long nativeCanvas, float x, float y, long nativePaint) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -544,7 +544,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count, + public static void nDrawPoints(long nativeCanvas, float[] pts, int offset, int count, long nativePaint) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -552,7 +552,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawLine(long nativeCanvas, + public static void nDrawLine(long nativeCanvas, final float startX, final float startY, final float stopX, final float stopY, long paint) { draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, @@ -565,7 +565,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawLines(long nativeCanvas, + public static void nDrawLines(long nativeCanvas, final float[] pts, final int offset, final int count, long nativePaint) { draw(nativeCanvas, nativePaint, false /*compositeOnly*/, @@ -581,7 +581,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawRect(long nativeCanvas, + public static void nDrawRect(long nativeCanvas, final float left, final float top, final float right, final float bottom, long paint) { draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, @@ -607,7 +607,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawOval(long nativeCanvas, final float left, + public static void nDrawOval(long nativeCanvas, final float left, final float top, final float right, final float bottom, long paint) { if (right > left && bottom > top) { draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, @@ -634,15 +634,15 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawCircle(long nativeCanvas, + public static void nDrawCircle(long nativeCanvas, float cx, float cy, float radius, long paint) { - native_drawOval(nativeCanvas, + nDrawOval(nativeCanvas, cx - radius, cy - radius, cx + radius, cy + radius, paint); } @LayoutlibDelegate - public static void native_drawArc(long nativeCanvas, + public static void nDrawArc(long nativeCanvas, final float left, final float top, final float right, final float bottom, final float startAngle, final float sweep, final boolean useCenter, long paint) { @@ -674,7 +674,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawRoundRect(long nativeCanvas, + public static void nDrawRoundRect(long nativeCanvas, final float left, final float top, final float right, final float bottom, final float rx, final float ry, long paint) { draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, @@ -704,7 +704,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawPath(long nativeCanvas, long path, long paint) { + public static void nDrawPath(long nativeCanvas, long path, long paint) { final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path); if (pathDelegate == null) { return; @@ -756,7 +756,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawRegion(long nativeCanvas, long nativeRegion, + public static void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -764,7 +764,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas, + public static void nDrawNinePatch(Canvas thisCanvas, long nativeCanvas, long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop, final float dstRight, final float dstBottom, long nativePaintOrZero, final int screenDensity, final int bitmapDensity) { @@ -811,7 +811,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap, + public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap, float left, float top, long nativePaintOrZero, int canvasDensity, @@ -833,7 +833,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap, + public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity) { @@ -849,7 +849,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawBitmap(long nativeCanvas, int[] colors, + public static void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, final float x, final float y, int width, int height, boolean hasAlpha, @@ -936,25 +936,25 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawText(long nativeCanvas, char[] text, int index, int count, + public static void nDrawText(long nativeCanvas, char[] text, int index, int count, float startX, float startY, int flags, long paint, long typeface) { drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0, paint, typeface); } @LayoutlibDelegate - public static void native_drawText(long nativeCanvas, String text, + public static void nDrawText(long nativeCanvas, String text, int start, int end, float x, float y, final int flags, long paint, long typeface) { int count = end - start; char[] buffer = TemporaryBuffer.obtain(count); TextUtils.getChars(text, start, end, buffer, 0); - native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface); + nDrawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface); } @LayoutlibDelegate - public static void native_drawTextRun(long nativeCanvas, String text, + public static void nDrawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long paint, long typeface) { int count = end - start; @@ -965,14 +965,14 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawTextRun(long nativeCanvas, char[] text, + public static void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long paint, long typeface) { drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface); } @LayoutlibDelegate - public static void native_drawTextOnPath(long nativeCanvas, + public static void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long path, float hOffset, @@ -984,7 +984,7 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void native_drawTextOnPath(long nativeCanvas, + public static void nDrawTextOnPath(long nativeCanvas, String text, long path, float hOffset, float vOffset, diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index a503e50407ed..354f9191beda 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -27,6 +27,8 @@ import android.graphics.Matrix.ScaleToFit; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; +import libcore.util.NativeAllocationRegistry_Delegate; + /** * Delegate implementing the native methods of android.graphics.Matrix * @@ -47,6 +49,7 @@ public final class Matrix_Delegate { // ---- delegate manager ---- private static final DelegateManager<Matrix_Delegate> sManager = new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class); + private static long sFinalizer = -1; // ---- delegate data ---- private float mValues[] = new float[MATRIX_SIZE]; @@ -174,7 +177,7 @@ public final class Matrix_Delegate { // ---- native methods ---- @LayoutlibDelegate - /*package*/ static long native_create(long native_src_or_zero) { + /*package*/ static long nCreate(long native_src_or_zero) { // create the delegate Matrix_Delegate newDelegate = new Matrix_Delegate(); @@ -193,7 +196,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_isIdentity(long native_object) { + /*package*/ static boolean nIsIdentity(long native_object) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return false; @@ -203,7 +206,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_isAffine(long native_object) { + /*package*/ static boolean nIsAffine(long native_object) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return true; @@ -213,7 +216,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_rectStaysRect(long native_object) { + /*package*/ static boolean nRectStaysRect(long native_object) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return true; @@ -223,7 +226,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_reset(long native_object) { + /*package*/ static void nReset(long native_object) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -233,7 +236,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_set(long native_object, long other) { + /*package*/ static void nSet(long native_object, long other) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -248,7 +251,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setTranslate(long native_object, float dx, float dy) { + /*package*/ static void nSetTranslate(long native_object, float dx, float dy) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -258,7 +261,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setScale(long native_object, float sx, float sy, + /*package*/ static void nSetScale(long native_object, float sx, float sy, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { @@ -269,7 +272,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setScale(long native_object, float sx, float sy) { + /*package*/ static void nSetScale(long native_object, float sx, float sy) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -287,7 +290,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setRotate(long native_object, float degrees, float px, float py) { + /*package*/ static void nSetRotate(long native_object, float degrees, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -297,7 +300,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setRotate(long native_object, float degrees) { + /*package*/ static void nSetRotate(long native_object, float degrees) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -307,7 +310,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue, + /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { @@ -326,7 +329,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue) { + /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -336,7 +339,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setSkew(long native_object, float kx, float ky, + /*package*/ static void nSetSkew(long native_object, float kx, float ky, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { @@ -347,7 +350,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setSkew(long native_object, float kx, float ky) { + /*package*/ static void nSetSkew(long native_object, float kx, float ky) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -365,12 +368,12 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setConcat(long native_object, long a, long b) { + /*package*/ static void nSetConcat(long native_object, long a, long b) { if (a == native_object) { - native_preConcat(native_object, b); + nPreConcat(native_object, b); return; } else if (b == native_object) { - native_postConcat(native_object, a); + nPostConcat(native_object, a); return; } @@ -383,7 +386,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preTranslate(long native_object, float dx, float dy) { + /*package*/ static void nPreTranslate(long native_object, float dx, float dy) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.preTransform(getTranslate(dx, dy)); @@ -391,7 +394,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preScale(long native_object, float sx, float sy, + /*package*/ static void nPreScale(long native_object, float sx, float sy, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -400,7 +403,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preScale(long native_object, float sx, float sy) { + /*package*/ static void nPreScale(long native_object, float sx, float sy) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.preTransform(getScale(sx, sy)); @@ -408,7 +411,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preRotate(long native_object, float degrees, + /*package*/ static void nPreRotate(long native_object, float degrees, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -417,7 +420,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preRotate(long native_object, float degrees) { + /*package*/ static void nPreRotate(long native_object, float degrees) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -430,7 +433,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preSkew(long native_object, float kx, float ky, + /*package*/ static void nPreSkew(long native_object, float kx, float ky, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -439,7 +442,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preSkew(long native_object, float kx, float ky) { + /*package*/ static void nPreSkew(long native_object, float kx, float ky) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.preTransform(getSkew(kx, ky)); @@ -447,7 +450,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_preConcat(long native_object, long other_matrix) { + /*package*/ static void nPreConcat(long native_object, long other_matrix) { Matrix_Delegate d = sManager.getDelegate(native_object); Matrix_Delegate other = sManager.getDelegate(other_matrix); if (d != null && other != null) { @@ -456,7 +459,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postTranslate(long native_object, float dx, float dy) { + /*package*/ static void nPostTranslate(long native_object, float dx, float dy) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.postTransform(getTranslate(dx, dy)); @@ -464,7 +467,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postScale(long native_object, float sx, float sy, + /*package*/ static void nPostScale(long native_object, float sx, float sy, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -473,7 +476,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postScale(long native_object, float sx, float sy) { + /*package*/ static void nPostScale(long native_object, float sx, float sy) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.postTransform(getScale(sx, sy)); @@ -481,7 +484,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postRotate(long native_object, float degrees, + /*package*/ static void nPostRotate(long native_object, float degrees, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -490,7 +493,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postRotate(long native_object, float degrees) { + /*package*/ static void nPostRotate(long native_object, float degrees) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.postTransform(getRotate(degrees)); @@ -498,7 +501,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postSkew(long native_object, float kx, float ky, + /*package*/ static void nPostSkew(long native_object, float kx, float ky, float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { @@ -507,7 +510,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postSkew(long native_object, float kx, float ky) { + /*package*/ static void nPostSkew(long native_object, float kx, float ky) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d != null) { d.postTransform(getSkew(kx, ky)); @@ -515,7 +518,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_postConcat(long native_object, long other_matrix) { + /*package*/ static void nPostConcat(long native_object, long other_matrix) { Matrix_Delegate d = sManager.getDelegate(native_object); Matrix_Delegate other = sManager.getDelegate(other_matrix); if (d != null && other != null) { @@ -524,7 +527,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_setRectToRect(long native_object, RectF src, + /*package*/ static boolean nSetRectToRect(long native_object, RectF src, RectF dst, int stf) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { @@ -589,7 +592,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_setPolyToPoly(long native_object, float[] src, int srcIndex, + /*package*/ static boolean nSetPolyToPoly(long native_object, float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -599,7 +602,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_invert(long native_object, long inverse) { + /*package*/ static boolean nInvert(long native_object, long inverse) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return false; @@ -627,7 +630,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_mapPoints(long native_object, float[] dst, int dstIndex, + /*package*/ static void nMapPoints(long native_object, float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount, boolean isPts) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { @@ -642,7 +645,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_mapRect(long native_object, RectF dst, RectF src) { + /*package*/ static boolean nMapRect(long native_object, RectF dst, RectF src) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return false; @@ -652,7 +655,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static float native_mapRadius(long native_object, float radius) { + /*package*/ static float nMapRadius(long native_object, float radius) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return 0.f; @@ -667,7 +670,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_getValues(long native_object, float[] values) { + /*package*/ static void nGetValues(long native_object, float[] values) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -677,7 +680,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void native_setValues(long native_object, float[] values) { + /*package*/ static void nSetValues(long native_object, float[] values) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { return; @@ -687,7 +690,7 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static boolean native_equals(long native_a, long native_b) { + /*package*/ static boolean nEquals(long native_a, long native_b) { Matrix_Delegate a = sManager.getDelegate(native_a); if (a == null) { return false; @@ -708,8 +711,13 @@ public final class Matrix_Delegate { } @LayoutlibDelegate - /*package*/ static void finalizer(long native_instance) { - sManager.removeJavaReferenceFor(native_instance); + /*package*/ static long nGetNativeFinalizer() { + synchronized (Matrix_Delegate.class) { + if (sFinalizer == -1) { + sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor); + } + } + return sFinalizer; } // ---- Private helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index 33296e1abdc9..0bbe33dc58df 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -261,7 +261,7 @@ public class Paint_Delegate { // ---- native methods ---- @LayoutlibDelegate - /*package*/ static int nGetFlags(Paint thisPaint, long nativePaint) { + /*package*/ static int nGetFlags(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -274,7 +274,7 @@ public class Paint_Delegate { @LayoutlibDelegate - /*package*/ static void nSetFlags(Paint thisPaint, long nativePaint, int flags) { + /*package*/ static void nSetFlags(long nativePaint, int flags) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -285,12 +285,12 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetFilterBitmap(Paint thisPaint, long nativePaint, boolean filter) { + /*package*/ static void nSetFilterBitmap(long nativePaint, boolean filter) { setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter); } @LayoutlibDelegate - /*package*/ static int nGetHinting(Paint thisPaint, long nativePaint) { + /*package*/ static int nGetHinting(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -301,7 +301,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetHinting(Paint thisPaint, long nativePaint, int mode) { + /*package*/ static void nSetHinting(long nativePaint, int mode) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -312,46 +312,46 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetAntiAlias(Paint thisPaint, long nativePaint, boolean aa) { + /*package*/ static void nSetAntiAlias(long nativePaint, boolean aa) { setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa); } @LayoutlibDelegate - /*package*/ static void nSetSubpixelText(Paint thisPaint, long nativePaint, + /*package*/ static void nSetSubpixelText(long nativePaint, boolean subpixelText) { setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText); } @LayoutlibDelegate - /*package*/ static void nSetUnderlineText(Paint thisPaint, long nativePaint, + /*package*/ static void nSetUnderlineText(long nativePaint, boolean underlineText) { setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText); } @LayoutlibDelegate - /*package*/ static void nSetStrikeThruText(Paint thisPaint, long nativePaint, + /*package*/ static void nSetStrikeThruText(long nativePaint, boolean strikeThruText) { setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText); } @LayoutlibDelegate - /*package*/ static void nSetFakeBoldText(Paint thisPaint, long nativePaint, + /*package*/ static void nSetFakeBoldText(long nativePaint, boolean fakeBoldText) { setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText); } @LayoutlibDelegate - /*package*/ static void nSetDither(Paint thisPaint, long nativePaint, boolean dither) { + /*package*/ static void nSetDither(long nativePaint, boolean dither) { setFlag(nativePaint, Paint.DITHER_FLAG, dither); } @LayoutlibDelegate - /*package*/ static void nSetLinearText(Paint thisPaint, long nativePaint, boolean linearText) { + /*package*/ static void nSetLinearText(long nativePaint, boolean linearText) { setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText); } @LayoutlibDelegate - /*package*/ static int nGetColor(Paint thisPaint, long nativePaint) { + /*package*/ static int nGetColor(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -362,7 +362,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetColor(Paint thisPaint, long nativePaint, int color) { + /*package*/ static void nSetColor(long nativePaint, int color) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -373,7 +373,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetAlpha(Paint thisPaint, long nativePaint) { + /*package*/ static int nGetAlpha(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -384,7 +384,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetAlpha(Paint thisPaint, long nativePaint, int a) { + /*package*/ static void nSetAlpha(long nativePaint, int a) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -395,7 +395,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nGetStrokeWidth(Paint thisPaint, long nativePaint) { + /*package*/ static float nGetStrokeWidth(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -406,7 +406,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetStrokeWidth(Paint thisPaint, long nativePaint, float width) { + /*package*/ static void nSetStrokeWidth(long nativePaint, float width) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -417,7 +417,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nGetStrokeMiter(Paint thisPaint, long nativePaint) { + /*package*/ static float nGetStrokeMiter(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -428,7 +428,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetStrokeMiter(Paint thisPaint, long nativePaint, float miter) { + /*package*/ static void nSetStrokeMiter(long nativePaint, float miter) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -455,14 +455,14 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static boolean nIsElegantTextHeight(Paint thisPaint, long nativePaint) { + /*package*/ static boolean nIsElegantTextHeight(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT; } @LayoutlibDelegate - /*package*/ static void nSetElegantTextHeight(Paint thisPaint, long nativePaint, + /*package*/ static void nSetElegantTextHeight(long nativePaint, boolean elegant) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); @@ -474,7 +474,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nGetTextSize(Paint thisPaint, long nativePaint) { + /*package*/ static float nGetTextSize(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -485,7 +485,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetTextSize(Paint thisPaint, long nativePaint, float textSize) { + /*package*/ static void nSetTextSize(long nativePaint, float textSize) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -499,7 +499,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nGetTextScaleX(Paint thisPaint, long nativePaint) { + /*package*/ static float nGetTextScaleX(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -510,7 +510,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetTextScaleX(Paint thisPaint, long nativePaint, float scaleX) { + /*package*/ static void nSetTextScaleX(long nativePaint, float scaleX) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -524,7 +524,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nGetTextSkewX(Paint thisPaint, long nativePaint) { + /*package*/ static float nGetTextSkewX(long nativePaint) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -535,7 +535,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static void nSetTextSkewX(Paint thisPaint, long nativePaint, float skewX) { + /*package*/ static void nSetTextSkewX(long nativePaint, float skewX) { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -549,7 +549,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nAscent(Paint thisPaint, long nativePaint, long nativeTypeface) { + /*package*/ static float nAscent(long nativePaint, long nativeTypeface) { // get the delegate Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -566,7 +566,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nDescent(Paint thisPaint, long nativePaint, long nativeTypeface) { + /*package*/ static float nDescent(long nativePaint, long nativeTypeface) { // get the delegate Paint_Delegate delegate = sManager.getDelegate(nativePaint); if (delegate == null) { @@ -583,7 +583,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float nGetFontMetrics(Paint thisPaint, long nativePaint, long nativeTypeface, + /*package*/ static float nGetFontMetrics(long nativePaint, long nativeTypeface, FontMetrics metrics) { // get the delegate Paint_Delegate delegate = sManager.getDelegate(nativePaint); @@ -595,7 +595,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetFontMetricsInt(Paint thisPaint, long nativePaint, + /*package*/ static int nGetFontMetricsInt(long nativePaint, long nativeTypeface, FontMetricsInt fmi) { // get the delegate Paint_Delegate delegate = sManager.getDelegate(nativePaint); @@ -998,7 +998,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, char[] text, + /*package*/ static int nGetTextRunCursor(long native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -1007,7 +1007,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, String text, + /*package*/ static int nGetTextRunCursor(long native_object, String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java index 3e81e834e6e6..99042638102a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java @@ -141,12 +141,12 @@ public class VectorDrawable_Delegate { long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) { VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr); - Canvas_Delegate.native_save(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); - Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.left, bounds.top); + Canvas_Delegate.nSave(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); + Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.left, bounds.top); if (needsMirroring) { - Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.width(), 0); - Canvas_Delegate.native_scale(canvasWrapperPtr, -1.0f, 1.0f); + Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.width(), 0); + Canvas_Delegate.nScale(canvasWrapperPtr, -1.0f, 1.0f); } // At this point, canvas has been translated to the right position. @@ -155,7 +155,7 @@ public class VectorDrawable_Delegate { bounds.offsetTo(0, 0); nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height()); - Canvas_Delegate.native_restore(canvasWrapperPtr, true); + Canvas_Delegate.nRestore(canvasWrapperPtr, true); return bounds.width() * bounds.height(); } @@ -1108,7 +1108,7 @@ public class VectorDrawable_Delegate { currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix); // Save the current clip information, which is local to this group. - Canvas_Delegate.native_save(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); + Canvas_Delegate.nSave(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); // Draw the group tree in the same order as the XML file. for (int i = 0; i < currentGroup.mChildren.size(); i++) { Object child = currentGroup.mChildren.get(i); @@ -1121,7 +1121,7 @@ public class VectorDrawable_Delegate { drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr); } } - Canvas_Delegate.native_restore(canvasPtr, true); + Canvas_Delegate.nRestore(canvasPtr, true); } public void draw(long canvasPtr, long filterPtr, int w, int h) { @@ -1153,7 +1153,7 @@ public class VectorDrawable_Delegate { if (VPath.isClipPath()) { mRenderPath.addPath(path, mFinalPathMatrix); - Canvas_Delegate.native_clipPath(canvasPtr, mRenderPath.mNativePath, Op + Canvas_Delegate.nClipPath(canvasPtr, mRenderPath.mNativePath, Op .INTERSECT.nativeInt); } else { VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath; @@ -1197,7 +1197,7 @@ public class VectorDrawable_Delegate { fillPaintDelegate.setColorFilter(filterPtr); fillPaintDelegate.setShader(fullPath.mFillGradient); Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType); - Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint + Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint .getNativeInstance()); } @@ -1228,7 +1228,7 @@ public class VectorDrawable_Delegate { final float finalStrokeScale = minScale * matrixScale; strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale); strokePaintDelegate.setShader(fullPath.mStrokeGradient); - Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint + Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, strokePaint .getNativeInstance()); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java index e4cbb2f4c02d..3471165e196b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java @@ -145,4 +145,10 @@ public final class BridgeContentProvider implements IContentProvider { public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException { return null; } + + @Override + public boolean refresh(String callingPkg, Uri url, Bundle args, + ICancellationSignal cancellationSignal) throws RemoteException { + return false; + } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index a0b297701869..1b3b563fb51e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -374,7 +374,9 @@ public final class BridgeContext extends Context { return true; } - return false; + // If the value is not a valid reference, fallback to pass the value as a string. + outValue.string = value.getValue(); + return true; } 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/tools/layoutlib/bridge/tests/res/empty.xml b/tools/layoutlib/bridge/tests/res/empty.xml new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/empty.xml diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle index 4561e1b80125..478166022d73 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle @@ -19,12 +19,12 @@ allprojects { apply plugin: 'com.android.application' android { - compileSdkVersion 22 - buildToolsVersion '21.1.2' + compileSdkVersion 25 + buildToolsVersion '25.0.0' defaultConfig { applicationId 'com.android.layoutlib.test.myapplication' minSdkVersion 21 - targetSdkVersion 22 + targetSdkVersion 25 versionCode 1 versionName '1.0' } @@ -34,6 +34,9 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + lintOptions { + abortOnError false + } compileOptions { sourceCompatibility JavaVersion.VERSION_1_6 targetCompatibility JavaVersion.VERSION_1_6 diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class Binary files differindex e0373cba84a7..f73528a556e2 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class Binary files differdeleted file mode 100644 index c3630552c7fe..000000000000 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class +++ /dev/null diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class Binary files differdeleted file mode 100644 index edda3de57058..000000000000 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class +++ /dev/null diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class Binary files differindex ec42017bad67..5bb04fc88caa 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class Binary files differnew file mode 100644 index 000000000000..ff699d1412dc --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class Binary files differindex 0e208f2dc7de..a3931b839c80 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class Binary files differindex 2b77af367a38..e2936771bfa4 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class Binary files differindex fd01b445df0d..d6268bf9601e 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class Binary files differindex 91cf5b6d824b..08b98fbb6f04 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class Binary files differindex 6c351da69d69..f9be1ca4583c 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class Binary files differindex aecbff6add3b..6874b49eb009 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class Binary files differindex fc3f23600d86..a4205a8c4e94 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class Binary files differindex 83ad35bd0ab1..4fb3b61bf9d4 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class Binary files differindex 6d7c71995eaf..dba67fd7efcc 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png Binary files differindex 9bf302ad6906..f274dbfbbdd6 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java index 41d75de7ada7..e7f22bfba00a 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.layoutlib.test.myapplication; import android.content.Context; diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java index 80bbaf139b4c..3b819e58e45e 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java @@ -1,4 +1,20 @@ -package com.android.layoutlib.test.myapplication; +/* + * 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.layoutlib.test.myapplication.widgets; import android.content.Context; import android.util.AttributeSet; @@ -26,6 +42,6 @@ public class CustomCalendar extends CalendarView { } private void init() { - setDate(871703200000L, false, true); + setDate(871732800000L, false, true); } } diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java index cb750f49322b..f3877f1b3d90 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java @@ -1,4 +1,20 @@ -package com.android.layoutlib.test.myapplication; +/* + * 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.layoutlib.test.myapplication.widgets; import android.content.Context; import android.util.AttributeSet; diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/package-info.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/package-info.java new file mode 100644 index 000000000000..58ad46deec2a --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/package-info.java @@ -0,0 +1,6 @@ +/** + * This package contains custom widgets used to set a specific time for the DayTimePicker during + * testing. + * The classes here are both used from the Android project and from the Bridge test project. + */ +package com.android.layoutlib.test.myapplication.widgets;
\ No newline at end of file diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml index 50646ab4c388..e9aa9e1378fb 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<com.android.layoutlib.test.myapplication.ArraysCheckWidget xmlns:android="http://schemas.android.com/apk/res/android" +<com.android.layoutlib.test.myapplication.ArraysCheckWidget + xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml index c1f663e9fa8a..ff14ce0a6298 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml @@ -15,10 +15,10 @@ android:checked="true" android:layout_gravity="center" /> - <com.android.layoutlib.test.myapplication.CustomDate + <com.android.layoutlib.test.myapplication.widgets.CustomDate android:layout_width="100dp" android:layout_height="wrap_content"/> - <com.android.layoutlib.test.myapplication.CustomCalendar + <com.android.layoutlib.test.myapplication.widgets.CustomCalendar android:layout_width="200dp" android:layout_gravity="center_horizontal" android:layout_height="200dp"/> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml index 88c9cbcb250a..c8a5fec71f09 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml @@ -3,7 +3,7 @@ <!-- Base application theme. --> <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar"> <item name="myattr">@integer/ten</item> - <!-- Customize your theme here. --> + <item name="android:animateFirstView">false</item> </style> </resources> diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index e7c6cc9faa19..5423e876e23f 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -39,6 +39,7 @@ import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; import com.android.resources.Density; import com.android.resources.Navigation; import com.android.resources.ResourceType; +import com.android.tools.layoutlib.java.System_Delegate; import com.android.utils.ILogger; import org.junit.AfterClass; @@ -51,6 +52,7 @@ import org.junit.runner.Description; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.PackageInstaller.Session; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; @@ -58,11 +60,28 @@ import android.util.DisplayMetrics; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.ref.WeakReference; +import java.net.MalformedURLException; import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import com.google.android.collect.Lists; @@ -105,6 +124,8 @@ public class Main { private static final String APP_TEST_DIR = "/testApp/MyApplication"; /** Location of the app's res dir inside {@link #TEST_RES_DIR}*/ private static final String APP_TEST_RES = APP_TEST_DIR + "/src/main/res"; + private static final String APP_CLASSES_LOCATION = + APP_TEST_DIR + "/build/intermediates/classes/debug/"; private static LayoutLog sLayoutLibLog; private static FrameworkResources sFrameworkRepo; @@ -115,6 +136,11 @@ public class Main { /** List of log messages generated by a render call. It can be used to find specific errors */ private static ArrayList<String> sRenderMessages = Lists.newArrayList(); + // Default class loader with access to the app classes + private ClassLoader mDefaultClassLoader = + new URLClassLoader(new URL[]{this.getClass().getResource(APP_CLASSES_LOCATION)}, + getClass().getClassLoader()); + @Rule public TestWatcher sRenderMessageWatcher = new TestWatcher() { @Override @@ -192,6 +218,7 @@ public class Main { } File[] hosts = host.listFiles(path -> path.isDirectory() && (path.getName().startsWith("linux-") || path.getName().startsWith("darwin-"))); + assert hosts != null; for (File hostOut : hosts) { String platformDir = getPlatformDirFromHostOut(hostOut); if (platformDir != null) { @@ -213,6 +240,7 @@ public class Main { // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7) return path.isDirectory() && path.getName().startsWith("sdk"); }); + assert sdkDirs != null; for (File dir : sdkDirs) { String platformDir = getPlatformDirFromHostOutSdkSdk(dir); if (platformDir != null) { @@ -225,6 +253,7 @@ public class Main { private static String getPlatformDirFromHostOutSdkSdk(File sdkDir) { File[] possibleSdks = sdkDir.listFiles( path -> path.isDirectory() && path.getName().contains("android-sdk")); + assert possibleSdks != null; for (File possibleSdk : possibleSdks) { File platformsDir = new File(possibleSdk, "platforms"); File[] platforms = platformsDir.listFiles( @@ -309,21 +338,51 @@ public class Main { /** Test activity.xml */ @Test public void testActivity() throws ClassNotFoundException { - try { - renderAndVerify("activity.xml", "activity.png"); - } catch (AssertionError e) { - // This is a KI in CalendarWidget and DatePicker rendering. - // Tracker bug: http://b.android.com/214370 - if (!e.getLocalizedMessage().startsWith("Images differ (by 6.5%)")) { - throw e; - } + renderAndVerify("activity.xml", "activity.png"); + } + + private static void gc() { + // See RuntimeUtil#gc in jlibs (http://jlibs.in/) + Object obj = new Object(); + WeakReference ref = new WeakReference<>(obj); + //noinspection UnusedAssignment + obj = null; + while(ref.get() != null) { + System.gc(); + System.runFinalization(); } + + System.gc(); + System.runFinalization(); + } + + /** Test allwidgets.xml */ + @Test + public void testAllWidgets() throws ClassNotFoundException { + renderAndVerify("allwidgets.xml", "allwidgets.png"); + + // We expect fidelity warnings for Path.isConvex. Fail for anything else. + sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); + } + + @Test + public void testArrayCheck() throws ClassNotFoundException { + renderAndVerify("array_check.xml", "array_check.png"); + } + + @Test + public void testAllWidgetsTablet() throws ClassNotFoundException { + renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012); + + // We expect fidelity warnings for Path.isConvex. Fail for anything else. + sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); } @Test public void testActivityActionBar() throws ClassNotFoundException { LayoutPullParser parser = createLayoutPullParser("simple_activity.xml"); - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, @@ -349,42 +408,6 @@ public class Main { renderAndVerify(params, "simple_activity.png"); } - /** Test allwidgets.xml */ - @Test - public void testAllWidgets() throws ClassNotFoundException { - renderAndVerify("allwidgets.xml", "allwidgets.png"); - - // We expect fidelity warnings for Path.isConvex. Fail for anything else. - sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); - } - - @Test - public void testArrayCheck() throws ClassNotFoundException { - renderAndVerify("array_check.xml", "array_check.png"); - } - - @Test - public void testAllWidgetsTablet() throws ClassNotFoundException { - renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012); - - // We expect fidelity warnings for Path.isConvex. Fail for anything else. - sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); - } - - private static void gc() { - // See RuntimeUtil#gc in jlibs (http://jlibs.in/) - Object obj = new Object(); - WeakReference ref = new WeakReference<Object>(obj); - obj = null; - while(ref.get() != null) { - System.gc(); - System.runFinalization(); - } - - System.gc(); - System.runFinalization(); - } - @AfterClass public static void tearDown() { sLayoutLibLog = null; @@ -405,7 +428,8 @@ public class Main { // Create the layout pull parser. LayoutPullParser parser = createLayoutPullParser("expand_vert_layout.xml"); // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); ConfigGenerator customConfigGenerator = new ConfigGenerator() @@ -439,7 +463,8 @@ public class Main { // Create the layout pull parser. LayoutPullParser parser = createLayoutPullParser("indeterminate_progressbar.xml"); // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, @@ -464,7 +489,8 @@ public class Main { // Create the layout pull parser. LayoutPullParser parser = createLayoutPullParser("vector_drawable.xml"); // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, @@ -482,7 +508,8 @@ public class Main { // Create the layout pull parser. LayoutPullParser parser = createLayoutPullParser("vector_drawable_android.xml"); // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, @@ -498,7 +525,8 @@ public class Main { // Create the layout pull parser. LayoutPullParser parser = createLayoutPullParser("scrolled.xml"); // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, @@ -509,6 +537,7 @@ public class Main { RenderResult result = renderAndVerify(params, "scrolled.png"); assertNotNull(result); + assertNotNull(result.getResult()); assertTrue(result.getResult().isSuccess()); ViewInfo rootLayout = result.getRootViews().get(0); @@ -528,7 +557,15 @@ public class Main { @Test public void testGetResourceNameVariants() throws Exception { // Setup - SessionParams params = createSessionParams("empty.xml", ConfigGenerator.NEXUS_4); + // Create the layout pull parser for our resources (empty.xml can not be part of the test + // app as it won't compile). + LayoutPullParser parser = new LayoutPullParser("/empty.xml"); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_4, + layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22); AssetManager assetManager = AssetManager.getSystem(); DisplayMetrics metrics = new DisplayMetrics(); Configuration configuration = RenderAction.getConfiguration(params); @@ -570,6 +607,8 @@ public class Main { throws ClassNotFoundException { // TODO: Set up action bar handler properly to test menu rendering. // Create session params. + System_Delegate.setBootTimeNanos(TimeUnit.MILLISECONDS.toNanos(871732800000L)); + System_Delegate.setNanosTime(TimeUnit.MILLISECONDS.toNanos(871732800000L)); RenderSession session = sBridge.createSession(params); if (frameTimeNanos != -1) { @@ -637,7 +676,8 @@ public class Main { // Create the layout pull parser. LayoutPullParser parser = createLayoutPullParser(layoutFileName); // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); layoutLibCallback.initResources(); // TODO: Set up action bar handler properly to test menu rendering. // Create session params. diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java index 96ae523006b3..bae2dc0c25f5 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java @@ -42,6 +42,9 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.util.Map; import com.google.android.collect.Maps; @@ -59,10 +62,11 @@ public class LayoutLibTestCallback extends LayoutlibCallback { private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap(); private final ILogger mLog; private final ActionBarCallback mActionBarCallback = new ActionBarCallback(); - private final ClassLoader mModuleClassLoader = new ModuleClassLoader(PROJECT_CLASSES_LOCATION); + private final ClassLoader mModuleClassLoader; - public LayoutLibTestCallback(ILogger logger) { + public LayoutLibTestCallback(ILogger logger, ClassLoader classLoader) { mLog = logger; + mModuleClassLoader = classLoader; } public void initResources() throws ClassNotFoundException { diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java deleted file mode 100644 index 110f4c8b9795..000000000000 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -package com.android.layoutlib.bridge.intensive.setup; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - -import com.google.android.collect.Maps; - -/** - * The ClassLoader to load the project's classes. - */ -public class ModuleClassLoader extends ClassLoader { - - private final Map<String, Class<?>> mClasses = Maps.newHashMap(); - private final String mClassLocation; - - public ModuleClassLoader(String classLocation) { - mClassLocation = classLocation; - } - - @Override - protected Class<?> findClass(String name) throws ClassNotFoundException { - Class<?> aClass = mClasses.get(name); - if (aClass != null) { - return aClass; - } - String pathName = mClassLocation.concat(name.replace('.', '/')).concat(".class"); - InputStream classInputStream = getClass().getResourceAsStream(pathName); - if (classInputStream == null) { - throw new ClassNotFoundException("Unable to find class " + name + " at " + pathName); - } - byte[] data; - try { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nRead; - data = new byte[16384]; // 16k - while ((nRead = classInputStream.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - buffer.flush(); - data = buffer.toByteArray(); - } catch (IOException e) { - // Wrap the exception with ClassNotFoundException so that caller can deal with it. - throw new ClassNotFoundException("Unable to load class " + name, e); - } - aClass = defineClass(name, data, 0, data.length); - mClasses.put(name, aClass); - return aClass; - } -} diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk index ce877b3696c2..09d95ffe3506 100644 --- a/tools/preload2/Android.mk +++ b/tools/preload2/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under,src) # To connect to devices (and take hprof dumps). -LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt +LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt tools-common-prebuilt # To process hprof dumps. LOCAL_STATIC_JAVA_LIBRARIES += perflib-prebuilt trove-prebuilt guavalib 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/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 017525b8511b..9e897bff1122 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -16,6 +16,7 @@ package android.net.wifi; +import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.ScanSettings; @@ -58,10 +59,11 @@ interface IWifiManager int addOrUpdateNetwork(in WifiConfiguration config); - int addPasspointManagementObject(String mo); + boolean addPasspointConfiguration(in PasspointConfiguration config); - int modifyPasspointManagementObject(String fqdn, - in List<PasspointManagementObjectDefinition> mos); + boolean removePasspointConfiguration(in String fqdn); + + List<PasspointConfiguration> getPasspointConfigurations(); void queryPasspointIcon(long bssid, String fileName); @@ -125,8 +127,6 @@ interface IWifiManager WifiConfiguration getWifiApConfiguration(); - WifiConfiguration buildWifiConfig(String uriString, String mimeType, in byte[] data); - void setWifiApConfiguration(in WifiConfiguration wifiConfig); Messenger getWifiServiceMessenger(); 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/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 8d5efba8620e..e48f7bdb27ee 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -22,6 +22,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; import android.text.TextUtils; +import java.lang.Math; import java.net.InetAddress; import java.net.Inet4Address; import java.net.UnknownHostException; @@ -136,6 +137,15 @@ public class WifiInfo implements Parcelable { */ public double rxSuccessRate; + private static final long RESET_TIME_STAMP = Long.MIN_VALUE; + private static final long FILTER_TIME_CONSTANT = 3000; + /** + * This factor is used to adjust the rate output under the new algorithm + * such that the result is comparable to the previous algorithm. + */ + private static final long OUTPUT_SCALE_FACTOR = 5000; + private long mLastPacketCountUpdateTimeStamp; + /** * @hide */ @@ -157,10 +167,9 @@ public class WifiInfo implements Parcelable { public int score; /** - * TODO: get actual timestamp and calculate true rates * @hide */ - public void updatePacketRates(WifiLinkLayerStats stats) { + public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) { if (stats != null) { long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo; long txretries = stats.retries_be + stats.retries_bk @@ -169,18 +178,28 @@ public class WifiInfo implements Parcelable { long txbad = stats.lostmpdu_be + stats.lostmpdu_bk + stats.lostmpdu_vi + stats.lostmpdu_vo; - if (txBad <= txbad + if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP + && mLastPacketCountUpdateTimeStamp < timeStamp + && txBad <= txbad && txSuccess <= txgood && rxSuccess <= rxgood && txRetries <= txretries) { - txBadRate = (txBadRate * 0.5) - + ((double) (txbad - txBad) * 0.5); - txSuccessRate = (txSuccessRate * 0.5) - + ((double) (txgood - txSuccess) * 0.5); - rxSuccessRate = (rxSuccessRate * 0.5) - + ((double) (rxgood - rxSuccess) * 0.5); - txRetriesRate = (txRetriesRate * 0.5) - + ((double) (txretries - txRetries) * 0.5); + long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp; + double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT); + double currentSampleWeight = 1.0 - lastSampleWeight; + + txBadRate = txBadRate * lastSampleWeight + + (txbad - txBad) * OUTPUT_SCALE_FACTOR / timeDelta + * currentSampleWeight; + txSuccessRate = txSuccessRate * lastSampleWeight + + (txgood - txSuccess) * OUTPUT_SCALE_FACTOR / timeDelta + * currentSampleWeight; + rxSuccessRate = rxSuccessRate * lastSampleWeight + + (rxgood - rxSuccess) * OUTPUT_SCALE_FACTOR / timeDelta + * currentSampleWeight; + txRetriesRate = txRetriesRate * lastSampleWeight + + (txretries - txRetries) * OUTPUT_SCALE_FACTOR / timeDelta + * currentSampleWeight; } else { txBadRate = 0; txSuccessRate = 0; @@ -191,6 +210,7 @@ public class WifiInfo implements Parcelable { txSuccess = txgood; rxSuccess = rxgood; txRetries = txretries; + mLastPacketCountUpdateTimeStamp = timeStamp; } else { txBad = 0; txSuccess = 0; @@ -200,6 +220,7 @@ public class WifiInfo implements Parcelable { txSuccessRate = 0; rxSuccessRate = 0; txRetriesRate = 0; + mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP; } } @@ -243,6 +264,7 @@ public class WifiInfo implements Parcelable { mRssi = INVALID_RSSI; mLinkSpeed = -1; mFrequency = -1; + mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP; } /** @hide */ @@ -268,6 +290,7 @@ public class WifiInfo implements Parcelable { badRssiCount = 0; linkStuckCount = 0; score = 0; + mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP; } /** @@ -295,6 +318,8 @@ public class WifiInfo implements Parcelable { txRetriesRate = source.txRetriesRate; txSuccessRate = source.txSuccessRate; rxSuccessRate = source.rxSuccessRate; + mLastPacketCountUpdateTimeStamp = + source.mLastPacketCountUpdateTimeStamp; score = source.score; badRssiCount = source.badRssiCount; lowRssiCount = source.lowRssiCount; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 18a580e03b6d..674c16156cc8 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -26,6 +26,7 @@ import android.net.DhcpInfo; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; +import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -841,30 +842,50 @@ public class WifiManager { } /** - * Add a Hotspot 2.0 release 2 Management Object - * @param mo The MO in XML form - * @return -1 for failure + * Add a Passpoint configuration. The configuration provides a credential + * for connecting to Passpoint networks that are operated by the Passpoint + * service provider specified in the configuration. + * + * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain + * Name). In the case when there is an existing configuration with the same base + * domain, the new configuration will replace the existing configuration. + * + * @param config The Passpoint configuration to be added + * @return true on success or false on failure * @hide */ - public int addPasspointManagementObject(String mo) { + public boolean addPasspointConfiguration(PasspointConfiguration config) { try { - return mService.addPasspointManagementObject(mo); + return mService.addPasspointConfiguration(config); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Modify a Hotspot 2.0 release 2 Management Object - * @param fqdn The FQDN of the service provider - * @param mos A List of MO definitions to be updated - * @return the number of nodes updated, or -1 for failure + * Remove a Passpoint configuration identified by its FQDN (Fully Qualified Domain Name). + * + * @param fqdn The FQDN of the passpoint configuration to be removed + * @return true on success or false on failure * @hide */ - public int modifyPasspointManagementObject(String fqdn, - List<PasspointManagementObjectDefinition> mos) { + public boolean removePasspointConfiguration(String fqdn) { try { - return mService.modifyPasspointManagementObject(fqdn, mos); + return mService.removePasspointConfiguration(fqdn); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Return the list of installed Passpoint configurations. + * + * @return A list of PasspointConfiguration or null + * @hide + */ + public List<PasspointConfiguration> getPasspointConfigurations() { + try { + return mService.getPasspointConfigurations(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1577,20 +1598,6 @@ public class WifiManager { } /** - * Builds a WifiConfiguration from Hotspot 2.0 MIME file. - * @return AP details in WifiConfiguration - * - * @hide Dont open yet - */ - public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) { - try { - return mService.buildWifiConfig(uriString, mimeType, data); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Sets the Wi-Fi AP Configuration. * @return {@code true} if the operation succeeded, {@code false} otherwise * diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java index 5d3ad0582f9c..ba493a024a13 100644 --- a/wifi/java/android/net/wifi/aware/PublishConfig.java +++ b/wifi/java/android/net/wifi/aware/PublishConfig.java @@ -32,9 +32,8 @@ import java.util.Arrays; /** * Defines the configuration of a Aware publish session. Built using * {@link PublishConfig.Builder}. A publish session is created using - * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig, - * WifiAwareDiscoverySessionCallback)} - * or updated using + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} or updated using * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}. * * @hide PROPOSED_AWARE_API diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index 2a6cc93146b4..5e14f8f761e0 100644 --- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java @@ -32,9 +32,8 @@ import java.util.Arrays; /** * Defines the configuration of a Aware subscribe session. Built using * {@link SubscribeConfig.Builder}. Subscribe is done using - * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig, - * WifiAwareDiscoverySessionCallback)} - * or + * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} or * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. * * @hide PROPOSED_AWARE_API @@ -403,8 +402,8 @@ public final class SubscribeConfig implements Parcelable { * Sets the match style of the subscription - how are matches from a * single match session (corresponding to the same publish action on the * peer) reported to the host (using the - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} - * ). The options are: only report the first match and ignore the rest + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])}). The options are: only report the first match and ignore the rest * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default). * diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java index 2cace6143f4f..1e8dbd945b6e 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java @@ -18,7 +18,7 @@ package android.net.wifi.aware; /** * Base class for Aware attach callbacks. Should be extended by applications and set when calling - * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}. These are callbacks + * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}. These are callbacks * applying to the Aware connection as a whole - not to specific publish or subscribe sessions - * for that see {@link WifiAwareDiscoverySessionCallback}. * @@ -27,7 +27,7 @@ package android.net.wifi.aware; public class WifiAwareAttachCallback { /** * Called when Aware attach operation - * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)} + * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)} * is completed and that we can now start discovery sessions or connections. * * @param session The Aware object on which we can execute further Aware operations - e.g. @@ -39,7 +39,7 @@ public class WifiAwareAttachCallback { /** * Called when Aware attach operation - * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)} failed. + * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)} failed. */ public void onAttachFailed() { /* empty */ diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java index 6232c14e0f18..072ccab1eb96 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java @@ -58,7 +58,8 @@ public class WifiAwareCharacteristics implements Parcelable { * message exchange. Restricts the parameters of the * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and - * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants. + * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])} + * variants. * * @return A positive integer, maximum length of byte array for Aware messaging. */ diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java index 07f752396d3d..e8335d11407a 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java @@ -32,10 +32,10 @@ import java.lang.ref.WeakReference; * {@link WifiAwarePublishDiscoverySession} and {@link WifiAwareSubscribeDiscoverySession}. This * class provides functionality common to both publish and subscribe discovery sessions: * <ul> - * <li>Sending messages: {@link #sendMessage(Object, int, byte[])} or - * {@link #sendMessage(Object, int, byte[], int)} methods. + * <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or + * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods. * <li>Creating a network-specifier when requesting a Aware connection: - * {@link #createNetworkSpecifier(int, Object, byte[])}. + * {@link #createNetworkSpecifier(int, WifiAwareManager.PeerHandle, byte[])}. * </ul> * The {@link #destroy()} method must be called to destroy discovery sessions once they are * no longer needed. @@ -62,7 +62,7 @@ public class WifiAwareDiscoveryBaseSession { /** * Return the maximum permitted retry count when sending messages using - * {@link #sendMessage(Object, int, byte[], int)}. + * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}. * * @return Maximum retry count when sending messages. */ @@ -139,21 +139,24 @@ public class WifiAwareDiscoveryBaseSession { /** * Sends a message to the specified destination. Aware messages are transmitted in the context * of a discovery session - executed subsequent to a publish/subscribe - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event. + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])} event. * <p> * Aware messages are not guaranteed delivery. Callbacks on * {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully, - * {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)}, or transmission failed - * (possibly after several retries) - + * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission + * failed (possibly after several retries) - * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}. * <p> * The peer will get a callback indicating a message was received using - * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}. + * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, + * byte[])}. * * @param peerHandle The peer's handle for the message. Must be a result of an - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} - * or - * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} events. + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])} or + * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, + * byte[])} events. * @param messageId An arbitrary integer used by the caller to identify the message. The same * integer ID will be returned in the callbacks indicating message send success or * failure. The {@code messageId} is not used internally by the Aware service - it @@ -164,8 +167,8 @@ public class WifiAwareDiscoveryBaseSession { * (note: no retransmissions are attempted in other failure cases). A value of 0 * indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}. */ - public void sendMessage(@NonNull Object peerHandle, int messageId, @Nullable byte[] message, - int retryCount) { + public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId, + @Nullable byte[] message, int retryCount) { if (mTerminated) { Log.w(TAG, "sendMessage: called on terminated session"); return; @@ -183,37 +186,43 @@ public class WifiAwareDiscoveryBaseSession { /** * Sends a message to the specified destination. Aware messages are transmitted in the context * of a discovery session - executed subsequent to a publish/subscribe - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event. + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])} event. * <p> * Aware messages are not guaranteed delivery. Callbacks on * {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully, - * {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)}, or transmission failed - * (possibly after several retries) - + * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission + * failed (possibly after several retries) - * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}. * <p> - * The peer will get a callback indicating a message was received using - * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}. - * Equivalent to {@link #sendMessage(Object, int, byte[], int)} with a {@code retryCount} of - * 0. + * The peer will get a callback indicating a message was received using + * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, + * byte[])}. + * Equivalent to {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} + * with a {@code retryCount} of 0. * * @param peerHandle The peer's handle for the message. Must be a result of an - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} - * or - * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} events. + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])} or + * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, + * byte[])} events. * @param messageId An arbitrary integer used by the caller to identify the message. The same * integer ID will be returned in the callbacks indicating message send success or * failure. The {@code messageId} is not used internally by the Aware service - it * can be arbitrary and non-unique. * @param message The message to be transmitted. */ - public void sendMessage(@NonNull Object peerHandle, int messageId, @Nullable byte[] message) { + public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId, + @Nullable byte[] message) { sendMessage(peerHandle, messageId, message, 0); } /** * Start a ranging operation with the specified peers. The peer IDs are obtained from an - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or - * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])} operation - can + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])} or + * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, + * byte[])} operation - can * only range devices which are part of an ongoing discovery session. * * @param params RTT parameters - each corresponding to a specific peer ID (the array sizes @@ -256,11 +265,12 @@ public class WifiAwareDiscoveryBaseSession { * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER} * @param peerHandle The peer's handle obtained through - * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or - * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(Object, byte[])}. On a RESPONDER - * this value is used to gate the acceptance of a connection request from only - * that peer. A RESPONDER may specified a null - indicating that it will accept - * connection requests from any device. + * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, + * byte[], byte[])} or + * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, + * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request + * from only that peer. A RESPONDER may specified a null - indicating that + * it will accept connection requests from any device. * @param token An arbitrary token (message) to be used to match connection initiation request * to a responder setup. A RESPONDER is set up with a {@code token} which must * be matched by the token provided by the INITIATOR. A null token is permitted @@ -274,7 +284,7 @@ public class WifiAwareDiscoveryBaseSession { * [or other varieties of that API]. */ public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role, - @Nullable Object peerHandle, @Nullable byte[] token) { + @Nullable WifiAwareManager.PeerHandle peerHandle, @Nullable byte[] token) { if (mTerminated) { Log.w(TAG, "createNetworkSpecifier: called on terminated session"); return null; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java index 9dfa24fd7232..6331c9c726c9 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java @@ -26,11 +26,10 @@ import java.lang.annotation.RetentionPolicy; * Base class for Aware session events callbacks. Should be extended by * applications wanting notifications. The callbacks are set when a * publish or subscribe session is created using - * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig, - * WifiAwareDiscoverySessionCallback)} - * or - * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig, - * WifiAwareDiscoverySessionCallback)} . + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} or + * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)}. * <p> * A single callback is set at session creation - it cannot be replaced. * @@ -62,9 +61,8 @@ public class WifiAwareDiscoverySessionCallback { /** * Called when a publish operation is started successfully in response to a - * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig, - * WifiAwareDiscoverySessionCallback)} - * operation. + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} operation. * * @param session The {@link WifiAwarePublishDiscoverySession} used to control the * discovery session. @@ -75,9 +73,8 @@ public class WifiAwareDiscoverySessionCallback { /** * Called when a subscribe operation is started successfully in response to a - * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig, - * WifiAwareDiscoverySessionCallback)} - * operation. + * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} operation. * * @param session The {@link WifiAwareSubscribeDiscoverySession} used to control the * discovery session. @@ -98,12 +95,10 @@ public class WifiAwareDiscoverySessionCallback { /** * Called when a publish or subscribe discovery session cannot be created: - * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig, - * WifiAwareDiscoverySessionCallback)} - * or - * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig, - * WifiAwareDiscoverySessionCallback)}, - * or when a configuration update fails: + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} or + * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)}, or when a configuration update fails: * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. * <p> @@ -138,13 +133,14 @@ public class WifiAwareDiscoverySessionCallback { * @param matchFilter The filter (Tx on advertiser and Rx on listener) which * resulted in this service discovery. */ - public void onServiceDiscovered(Object peerHandle, byte[] serviceSpecificInfo, - byte[] matchFilter) { + public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle, + byte[] serviceSpecificInfo, byte[] matchFilter) { /* empty */ } /** - * Called in response to {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} + * Called in response to + * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])} * when a message is transmitted successfully - i.e. when it was received successfully by the * peer (corresponds to an ACK being received). * <p> @@ -154,18 +150,18 @@ public class WifiAwareDiscoverySessionCallback { * * @param messageId The arbitrary message ID specified when sending the message. */ - public void onMessageSent(@SuppressWarnings("unused") int messageId) { + public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) { /* empty */ } /** * Called when message transmission fails - when no ACK is received from the peer. * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using - * the {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[], int)} method) - - * this event is received after all retries are exhausted. + * the {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, + * byte[], int)} method) - this event is received after all retries are exhausted. * <p> * Note that either this callback or - * {@link WifiAwareDiscoverySessionCallback#onMessageSent(int)} will be received + * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)} will be received * - never both. * * @param messageId The arbitrary message ID specified when sending the message. @@ -176,13 +172,14 @@ public class WifiAwareDiscoverySessionCallback { /** * Called when a message is received from a discovery session peer - in response to the - * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} or - * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[], int)}. + * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, + * byte[])} or {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, + * int, byte[], int)}. * * @param peerHandle An opaque handle to the peer matching our discovery operation. * @param message A byte array containing the message. */ - public void onMessageReceived(Object peerHandle, byte[] message) { + public void onMessageReceived(WifiAwareManager.PeerHandle peerHandle, byte[] message) { /* empty */ } } diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 5528ff839ede..a34ef4777d65 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -56,14 +56,14 @@ import java.util.Arrays; * The class provides access to: * <ul> * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to - * {@link #attach(Handler, WifiAwareAttachCallback)}. + * {@link #attach(WifiAwareAttachCallback, Handler)}. * <li>Create discovery sessions (publish or subscribe sessions). Refer to - * {@link WifiAwareSession#publish(Handler, PublishConfig, WifiAwareDiscoverySessionCallback)} and - * {@link WifiAwareSession#subscribe(Handler, SubscribeConfig, WifiAwareDiscoverySessionCallback)}. + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)} and + * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, Handler)}. * <li>Create a Aware network specifier to be used with * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)} * to set-up a Aware connection with a peer. Refer to - * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])} and + * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])} and * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}. * </ul> * <p> @@ -73,7 +73,7 @@ import java.util.Arrays; * broadcast. Note that this broadcast is not sticky - you should register for it and then * check the above API to avoid a race condition. * <p> - * An application must use {@link #attach(Handler, WifiAwareAttachCallback)} to initialize a + * An application must use {@link #attach(WifiAwareAttachCallback, Handler)} to initialize a * Aware cluster - before making any other Aware operation. Aware cluster membership is a * device-wide operation - the API guarantees that the device is in a cluster or joins a * Aware cluster (or starts one if none can be found). Information about attach success (or @@ -86,12 +86,11 @@ import java.util.Arrays; * application detaches. * <p> * Once a Aware attach is confirmed use the - * {@link WifiAwareSession#publish(Handler, PublishConfig, WifiAwareDiscoverySessionCallback)} + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)} * or - * {@link WifiAwareSession#subscribe(Handler, SubscribeConfig, - * WifiAwareDiscoverySessionCallback)} - * to create publish or subscribe Aware discovery sessions. Events are called on the provided - * callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the + * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, + * Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the + * provided callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)} * and * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted( @@ -102,7 +101,7 @@ import java.util.Arrays; * the session {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} and * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can * also be used to send messages using the - * {@link WifiAwareDiscoveryBaseSession#sendMessage(Object, int, byte[])} APIs. When an + * {@link WifiAwareDiscoveryBaseSession#sendMessage(PeerHandle, int, byte[])} APIs. When an * application is finished with a discovery session it <b>must</b> terminate it using the * {@link WifiAwareDiscoveryBaseSession#destroy()} API. * <p> @@ -115,7 +114,7 @@ import java.util.Arrays; * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. * <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or - * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}. + * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])}. * </ul> * * @hide PROPOSED_AWARE_API @@ -225,7 +224,7 @@ public class WifiAwareManager { * Connection creation role is that of INITIATOR. Used to create a network specifier string * when requesting a Aware network. * - * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[]) + * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[]) * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[]) */ public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; @@ -234,7 +233,7 @@ public class WifiAwareManager { * Connection creation role is that of RESPONDER. Used to create a network specifier string * when requesting a Aware network. * - * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[]) + * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[]) * @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[]) */ public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; @@ -304,6 +303,7 @@ public class WifiAwareManager { * limitations on configurations, e.g. the maximum service name length. * * @return An object specifying configuration limitations of Aware. + * @hide PROPOSED_AWARE_API */ public WifiAwareCharacteristics getCharacteristics() { try { @@ -325,13 +325,13 @@ public class WifiAwareManager { * then this function will simply indicate success immediately using the same {@code * attachCallback}. * + * @param attachCallback A callback for attach events, extended from + * {@link WifiAwareAttachCallback}. * @param handler The Handler on whose thread to execute the callbacks of the {@code * attachCallback} object. If a null is provided then the application's main thread will be * used. - * @param attachCallback A callback for attach events, extended from - * {@link WifiAwareAttachCallback}. */ - public void attach(@Nullable Handler handler, @NonNull WifiAwareAttachCallback attachCallback) { + public void attach(@NonNull WifiAwareAttachCallback attachCallback, @Nullable Handler handler) { attach(handler, null, attachCallback, null); } @@ -351,20 +351,21 @@ public class WifiAwareManager { * on startup and whenever it is updated (it is randomized at regular intervals for privacy). * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} * permission to execute this attach request. Otherwise, use the - * {@link #attach(Handler, WifiAwareAttachCallback)} version. Note that aside from permission + * {@link #attach(WifiAwareAttachCallback, Handler)} version. Note that aside from permission * requirements this listener will wake up the host at regular intervals causing higher power * consumption, do not use it unless the information is necessary (e.g. for OOB discovery). * - * @param handler The Handler on whose thread to execute the callbacks of the {@code - * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the - * application's main thread will be used. * @param attachCallback A callback for attach events, extended from * {@link WifiAwareAttachCallback}. * @param identityChangedListener A listener for changed identity, extended from * {@link WifiAwareIdentityChangedListener}. + * @param handler The Handler on whose thread to execute the callbacks of the {@code + * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the + * application's main thread will be used. */ - public void attach(@Nullable Handler handler, @NonNull WifiAwareAttachCallback attachCallback, - @NonNull WifiAwareIdentityChangedListener identityChangedListener) { + public void attach(@NonNull WifiAwareAttachCallback attachCallback, + @NonNull WifiAwareIdentityChangedListener identityChangedListener, + @Nullable Handler handler) { attach(handler, null, attachCallback, identityChangedListener); } @@ -480,7 +481,7 @@ public class WifiAwareManager { } /** @hide */ - public void sendMessage(int clientId, int sessionId, Object peerHandle, byte[] message, + public void sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message, int messageId, int retryCount) { if (peerHandle == null) { throw new IllegalArgumentException( @@ -489,13 +490,13 @@ public class WifiAwareManager { if (VDBG) { Log.v(TAG, "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId - + ", peerHandle=" + ((OpaquePeerHandle) peerHandle).peerId + ", messageId=" + + ", peerHandle=" + peerHandle.peerId + ", messageId=" + messageId + ", retryCount=" + retryCount); } try { - mService.sendMessage(clientId, sessionId, ((OpaquePeerHandle) peerHandle).peerId, - message, messageId, retryCount); + mService.sendMessage(clientId, sessionId, peerHandle.peerId, message, messageId, + retryCount); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -523,12 +524,12 @@ public class WifiAwareManager { } /** @hide */ - public String createNetworkSpecifier(int clientId, int role, int sessionId, Object peerHandle, - byte[] token) { + public String createNetworkSpecifier(int clientId, int role, int sessionId, + PeerHandle peerHandle, byte[] token) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId - + ", peerHandle=" + ((peerHandle == null) ? peerHandle - : ((OpaquePeerHandle) peerHandle).peerId) + ", token=" + token); + + ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId) + + ", token=" + token); } int type; @@ -568,7 +569,7 @@ public class WifiAwareManager { json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId); if (peerHandle != null) { - json.put(NETWORK_SPECIFIER_KEY_PEER_ID, ((OpaquePeerHandle) peerHandle).peerId); + json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId); } if (token != null) { json.put(NETWORK_SPECIFIER_KEY_TOKEN, @@ -875,18 +876,18 @@ public class WifiAwareManager { break; case CALLBACK_MATCH: mOriginalCallback.onServiceDiscovered( - new OpaquePeerHandle(msg.arg1), + new PeerHandle(msg.arg1), msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2)); break; case CALLBACK_MESSAGE_SEND_SUCCESS: - mOriginalCallback.onMessageSent(msg.arg1); + mOriginalCallback.onMessageSendSucceeded(msg.arg1); break; case CALLBACK_MESSAGE_SEND_FAIL: mOriginalCallback.onMessageSendFailed(msg.arg1); break; case CALLBACK_MESSAGE_RECEIVED: - mOriginalCallback.onMessageReceived(new OpaquePeerHandle(msg.arg1), + mOriginalCallback.onMessageReceived(new PeerHandle(msg.arg1), (byte[]) msg.obj); break; } @@ -1018,12 +1019,14 @@ public class WifiAwareManager { } } - /** @hide */ - public static class OpaquePeerHandle { - public OpaquePeerHandle(int peerId) { + /** @hide PROPOSED_AWARE_API */ + public static class PeerHandle { + /** @hide */ + public PeerHandle(int peerId) { this.peerId = peerId; } + /** @hide */ public int peerId; } } diff --git a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java index 610a92ce28b5..68786d17d38d 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java @@ -21,9 +21,8 @@ import android.util.Log; /** * A class representing a Aware publish session. Created when - * {@link WifiAwareSession#publish(android.os.Handler, PublishConfig, - * WifiAwareDiscoverySessionCallback)} - * is called and a discovery session is created and returned in + * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, + * android.os.Handler)} is called and a discovery session is created and returned in * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}. See * baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. This * object allows updating an existing/running publish discovery session using diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java index 357bd43f12db..acb60a4480d4 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -65,7 +65,7 @@ public class WifiAwareSession { * session-wide destroy. * <p> * An application may re-attach after a destroy using - * {@link WifiAwareManager#attach(Handler, WifiAwareAttachCallback)} . + * {@link WifiAwareManager#attach(WifiAwareAttachCallback, Handler)} . */ public void destroy() { WifiAwareManager mgr = mMgr.get(); @@ -116,15 +116,15 @@ public class WifiAwareSession { * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} * permission to start a publish discovery session. * - * @param handler The Handler on whose thread to execute the callbacks of the {@code - * callback} object. If a null is provided then the application's main thread will be used. * @param publishConfig The {@link PublishConfig} specifying the * configuration of the requested publish session. * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for * session event callbacks. + * @param handler The Handler on whose thread to execute the callbacks of the {@code + * callback} object. If a null is provided then the application's main thread will be used. */ - public void publish(@Nullable Handler handler, @NonNull PublishConfig publishConfig, - @NonNull WifiAwareDiscoverySessionCallback callback) { + public void publish(@NonNull PublishConfig publishConfig, + @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "publish: called post GC on WifiAwareManager"); @@ -162,15 +162,15 @@ public class WifiAwareSession { * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} * permission to start a subscribe discovery session. * - * @param handler The Handler on whose thread to execute the callbacks of the {@code - * callback} object. If a null is provided then the application's main thread will be used. * @param subscribeConfig The {@link SubscribeConfig} specifying the * configuration of the requested subscribe session. * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for * session event callbacks. + * @param handler The Handler on whose thread to execute the callbacks of the {@code + * callback} object. If a null is provided then the application's main thread will be used. */ - public void subscribe(@Nullable Handler handler, @NonNull SubscribeConfig subscribeConfig, - @NonNull WifiAwareDiscoverySessionCallback callback) { + public void subscribe(@NonNull SubscribeConfig subscribeConfig, + @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "publish: called post GC on WifiAwareManager"); @@ -193,7 +193,8 @@ public class WifiAwareSession { * This API is targeted for applications which can obtain the peer MAC address using OOB * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer - * when using Aware discovery use the alternative network specifier method - - * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}. + * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, + * WifiAwareManager.PeerHandle, byte[])}. * * @param role The role of this device: * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java index 7c48f549eaf4..a0ec8093a3ab 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java @@ -21,8 +21,8 @@ import android.util.Log; /** * A class representing a Aware subscribe session. Created when - * {@link WifiAwareSession#subscribe(android.os.Handler, SubscribeConfig, - * WifiAwareDiscoverySessionCallback)} + * {@link WifiAwareSession#subscribe(SubscribeConfig, + * WifiAwareDiscoverySessionCallback, android.os.Handler)} * is called and a discovery session is created and returned in * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(WifiAwareSubscribeDiscoverySession)}. * See baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java new file mode 100644 index 000000000000..96db5d02679e --- /dev/null +++ b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java @@ -0,0 +1,473 @@ +/** + * 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.hotspot2; + +import android.net.wifi.hotspot2.omadm.PPSMOParser; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; +import android.util.Pair; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Utility class for building PasspointConfiguration from an installation file. + * + * @hide + */ +public final class ConfigBuilder { + private static final String TAG = "ConfigBuilder"; + + // Header names. + private static final String CONTENT_TYPE = "Content-Type"; + private static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; + + // MIME types. + private static final String TYPE_MULTIPART_MIXED = "multipart/mixed"; + private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config"; + private static final String TYPE_PASSPOINT_PROFILE = "application/x-passpoint-profile"; + private static final String TYPE_CA_CERT = "application/x-x509-ca-cert"; + private static final String TYPE_PKCS12 = "application/x-pkcs12"; + + private static final String ENCODING_BASE64 = "base64"; + private static final String BOUNDARY = "boundary="; + + /** + * Class represent a MIME (Multipurpose Internet Mail Extension) part. + */ + private static class MimePart { + /** + * Content type of the part. + */ + public String type = null; + + /** + * Decoded data. + */ + public byte[] data = null; + + /** + * Flag indicating if this is the last part (ending with --{boundary}--). + */ + public boolean isLast = false; + } + + /** + * Class represent the MIME (Multipurpose Internet Mail Extension) header. + */ + private static class MimeHeader { + /** + * Content type. + */ + public String contentType = null; + + /** + * Boundary string (optional), only applies for the outter MIME header. + */ + public String boundary = null; + + /** + * Encoding type. + */ + public String encodingType = null; + } + + + /** + * Parse the Hotspot 2.0 Release 1 configuration data into a {@link PasspointConfiguration} + * object. The configuration data is a base64 encoded MIME multipart data. Below is + * the format of the decoded message: + * + * Content-Type: multipart/mixed; boundary={boundary} + * Content-Transfer-Encoding: base64 + * + * --{boundary} + * Content-Type: application/x-passpoint-profile + * Content-Transfer-Encoding: base64 + * + * [base64 encoded Passpoint profile data] + * --{boundary} + * Content-Type: application/x-x509-ca-cert + * Content-Transfer-Encoding: base64 + * + * [base64 encoded X509 CA certificate data] + * --{boundary} + * Content-Type: application/x-pkcs12 + * Content-Transfer-Encoding: base64 + * + * [base64 encoded PKCS#12 ASN.1 structure containing client certificate chain] + * --{boundary} + * + * @param mimeType MIME type of the encoded data. + * @param data A base64 encoded MIME multipart message containing the Passpoint profile + * (required), CA (Certificate Authority) certificate (optional), and client + * certificate chain (optional). + * @return {@link PasspointConfiguration} + */ + public static PasspointConfiguration buildPasspointConfig(String mimeType, byte[] data) { + // Verify MIME type. + if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) { + Log.e(TAG, "Unexpected MIME type: " + mimeType); + return null; + } + + try { + // Decode the data. + byte[] decodedData = Base64.decode(new String(data, StandardCharsets.ISO_8859_1), + Base64.DEFAULT); + Map<String, byte[]> mimeParts = parseMimeMultipartMessage(new LineNumberReader( + new InputStreamReader(new ByteArrayInputStream(decodedData), + StandardCharsets.ISO_8859_1))); + return createPasspointConfig(mimeParts); + } catch (IOException | IllegalArgumentException e) { + Log.e(TAG, "Failed to parse installation file: " + e.getMessage()); + return null; + } + } + + /** + * Create a {@link PasspointConfiguration} object from list of MIME (Multipurpose Internet + * Mail Extension) parts. + * + * @param mimeParts Map of content type and content data. + * @return {@link PasspointConfiguration} + * @throws IOException + */ + private static PasspointConfiguration createPasspointConfig(Map<String, byte[]> mimeParts) + throws IOException { + byte[] profileData = mimeParts.get(TYPE_PASSPOINT_PROFILE); + if (profileData == null) { + throw new IOException("Missing Passpoint Profile"); + } + + PasspointConfiguration config = PPSMOParser.parseMOText(new String(profileData)); + if (config == null) { + throw new IOException("Failed to parse Passpoint profile"); + } + + // Credential is needed for storing the certificates and private client key. + if (config.credential == null) { + throw new IOException("Passpoint profile missing credential"); + } + + // Parse CA (Certificate Authority) certificate. + byte[] caCertData = mimeParts.get(TYPE_CA_CERT); + if (caCertData != null) { + try { + config.credential.caCertificate = parseCACert(caCertData); + } catch (CertificateException e) { + throw new IOException("Failed to parse CA Certificate"); + } + } + + // Parse PKCS12 data for client private key and certificate chain. + byte[] pkcs12Data = mimeParts.get(TYPE_PKCS12); + if (pkcs12Data != null) { + try { + Pair<PrivateKey, List<X509Certificate>> clientKey = parsePkcs12(pkcs12Data); + config.credential.clientPrivateKey = clientKey.first; + config.credential.clientCertificateChain = + clientKey.second.toArray(new X509Certificate[clientKey.second.size()]); + } catch(GeneralSecurityException | IOException e) { + throw new IOException("Failed to parse PCKS12 string"); + } + } + return config; + } + + /** + * Parse a MIME (Multipurpose Internet Mail Extension) multipart message from the given + * input stream. + * + * @param in The input stream for reading the message data + * @return A map of a content type and content data pair + * @throws IOException + */ + private static Map<String, byte[]> parseMimeMultipartMessage(LineNumberReader in) + throws IOException { + // Parse the outer MIME header. + MimeHeader header = parseHeaders(in); + if (!TextUtils.equals(header.contentType, TYPE_MULTIPART_MIXED)) { + throw new IOException("Invalid content type: " + header.contentType); + } + if (TextUtils.isEmpty(header.boundary)) { + throw new IOException("Missing boundary string"); + } + if (!TextUtils.equals(header.encodingType, ENCODING_BASE64)) { + throw new IOException("Unexpected encoding: " + header.encodingType); + } + + // Read pass the first boundary string. + for (;;) { + String line = in.readLine(); + if (line == null) { + throw new IOException("Unexpected EOF before first boundary @ " + + in.getLineNumber()); + } + if (line.equals("--" + header.boundary)) { + break; + } + } + + // Parse each MIME part. + Map<String, byte[]> mimeParts = new HashMap<>(); + boolean isLast = false; + do { + MimePart mimePart = parseMimePart(in, header.boundary); + mimeParts.put(mimePart.type, mimePart.data); + isLast = mimePart.isLast; + } while(!isLast); + return mimeParts; + } + + /** + * Parse a MIME (Multipurpose Internet Mail Extension) part. We expect the data to + * be encoded in base64. + * + * @param in Input stream to read the data from + * @param boundary Boundary string indicate the end of the part + * @return {@link MimePart} + * @throws IOException + */ + private static MimePart parseMimePart(LineNumberReader in, String boundary) + throws IOException { + MimeHeader header = parseHeaders(in); + // Expect encoding type to be base64. + if (!TextUtils.equals(header.encodingType, ENCODING_BASE64)) { + throw new IOException("Unexpected encoding type: " + header.encodingType); + } + + // Check for a valid content type. + if (!TextUtils.equals(header.contentType, TYPE_PASSPOINT_PROFILE) && + !TextUtils.equals(header.contentType, TYPE_CA_CERT) && + !TextUtils.equals(header.contentType, TYPE_PKCS12)) { + throw new IOException("Unexpected content type: " + header.contentType); + } + + StringBuilder text = new StringBuilder(); + boolean isLast = false; + String partBoundary = "--" + boundary; + String endBoundary = partBoundary + "--"; + for (;;) { + String line = in.readLine(); + if (line == null) { + throw new IOException("Unexpected EOF file in body @ " + in.getLineNumber()); + } + // Check for boundary line. + if (line.startsWith(partBoundary)) { + if (line.equals(endBoundary)) { + isLast = true; + } + break; + } + text.append(line); + } + + MimePart part = new MimePart(); + part.type = header.contentType; + part.data = Base64.decode(text.toString(), Base64.DEFAULT); + part.isLast = isLast; + return part; + } + + /** + * Parse a MIME (Multipurpose Internet Mail Extension) header from the input stream. + * @param in Input stream to read from. + * @return {@link MimeHeader} + * @throws IOException + */ + private static MimeHeader parseHeaders(LineNumberReader in) + throws IOException { + MimeHeader header = new MimeHeader(); + + // Read the header from the input stream. + Map<String, String> headers = readHeaders(in); + + // Parse each header. + for (Map.Entry<String, String> entry : headers.entrySet()) { + switch (entry.getKey()) { + case CONTENT_TYPE: + Pair<String, String> value = parseContentType(entry.getValue()); + header.contentType = value.first; + header.boundary = value.second; + break; + case CONTENT_TRANSFER_ENCODING: + header.encodingType = entry.getValue(); + break; + default: + throw new IOException("Unexpected header: " + entry.getKey()); + } + } + return header; + } + + /** + * Parse the Content-Type header value. The value will contain the content type string and + * an optional boundary string separated by a ";". Below are examples of valid Content-Type + * header value: + * multipart/mixed; boundary={boundary} + * application/x-passpoint-profile + * + * @param contentType The Content-Type value string + * @return A pair of content type and boundary string + * @throws IOException + */ + private static Pair<String, String> parseContentType(String contentType) throws IOException { + String[] attributes = contentType.toString().split(";"); + String type = null; + String boundary = null; + + if (attributes.length < 1 || attributes.length > 2) { + throw new IOException("Invalid Content-Type: " + contentType); + } + + type = attributes[0].trim(); + if (attributes.length == 2) { + boundary = attributes[1].trim(); + if (!boundary.startsWith(BOUNDARY)) { + throw new IOException("Invalid Content-Type: " + contentType); + } + boundary = boundary.substring(BOUNDARY.length()); + // Remove the leading and trailing quote if present. + if (boundary.length() > 1 && boundary.startsWith("\"") && boundary.endsWith("\"")) { + boundary = boundary.substring(1, boundary.length()-1); + } + } + + return new Pair<String, String>(type, boundary); + } + + /** + * Read the headers from the given input stream. The header section is terminated by + * an empty line. + * + * @param in The input stream to read from + * @return Map of key-value pairs. + * @throws IOException + */ + private static Map<String, String> readHeaders(LineNumberReader in) + throws IOException { + Map<String, String> headers = new HashMap<>(); + String line; + String name = null; + StringBuilder value = null; + for (;;) { + line = in.readLine(); + if (line == null) { + throw new IOException("Missing line @ " + in.getLineNumber()); + } + + // End of headers section. + if (line.length() == 0 || line.trim().length() == 0) { + // Save the previous header line. + if (name != null) { + headers.put(name, value.toString()); + } + break; + } + + int nameEnd = line.indexOf(':'); + if (nameEnd < 0) { + if (value != null) { + // Continuation line for the header value. + value.append(' ').append(line.trim()); + } else { + throw new IOException("Bad header line: '" + line + "' @ " + + in.getLineNumber()); + } + } else { + // New header line detected, make sure it doesn't start with a whitespace. + if (Character.isWhitespace(line.charAt(0))) { + throw new IOException("Illegal blank prefix in header line '" + line + + "' @ " + in.getLineNumber()); + } + + if (name != null) { + // Save the previous header line. + headers.put(name, value.toString()); + } + + // Setup the current header line. + name = line.substring(0, nameEnd).trim(); + value = new StringBuilder(); + value.append(line.substring(nameEnd+1).trim()); + } + } + return headers; + } + + /** + * Parse a CA (Certificate Authority) certificate data and convert it to a + * X509Certificate object. + * + * @param octets Certificate data + * @return X509Certificate + * @throws CertificateException + */ + private static X509Certificate parseCACert(byte[] octets) throws CertificateException { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(octets)); + } + + private static Pair<PrivateKey, List<X509Certificate>> parsePkcs12(byte[] octets) + throws GeneralSecurityException, IOException { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ByteArrayInputStream in = new ByteArrayInputStream(octets); + ks.load(in, new char[0]); + in.close(); + + // Only expects one set of key and certificate chain. + if (ks.size() != 1) { + throw new IOException("Unexpected key size: " + ks.size()); + } + + String alias = ks.aliases().nextElement(); + if (alias == null) { + throw new IOException("No alias found"); + } + + PrivateKey clientKey = (PrivateKey) ks.getKey(alias, null); + List<X509Certificate> clientCertificateChain = null; + Certificate[] chain = ks.getCertificateChain(alias); + if (chain != null) { + clientCertificateChain = new ArrayList<>(); + for (Certificate certificate : chain) { + if (!(certificate instanceof X509Certificate)) { + throw new IOException("Unexpceted certificate type: " + + certificate.getClass()); + } + clientCertificateChain.add((X509Certificate) certificate); + } + } + return new Pair<PrivateKey, List<X509Certificate>>(clientKey, clientCertificateChain); + } +}
\ No newline at end of file diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 18aae534d098..643753abf5dc 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -36,6 +36,27 @@ public final class PasspointConfiguration implements Parcelable { public HomeSP homeSp = null; public Credential credential = null; + /** + * Constructor for creating PasspointConfiguration with default values. + */ + public PasspointConfiguration() {} + + /** + * Copy constructor. + * + * @param source The source to copy from + */ + public PasspointConfiguration(PasspointConfiguration source) { + if (source != null) { + if (source.homeSp != null) { + homeSp = new HomeSP(source.homeSp); + } + if (source.credential != null) { + credential = new Credential(source.credential); + } + } + } + @Override public int describeContents() { return 0; @@ -61,6 +82,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..790dfaf643ca 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; @@ -75,6 +109,25 @@ public final class Credential implements Parcelable { */ public String nonEapInnerMethod = null; + /** + * Constructor for creating UserCredential with default values. + */ + public UserCredential() {} + + /** + * Copy constructor. + * + * @param source The source to copy from + */ + public UserCredential(UserCredential source) { + if (source != null) { + username = source.username; + password = source.password; + eapType = source.eapType; + nonEapInnerMethod = source.nonEapInnerMethod; + } + } + @Override public int describeContents() { return 0; @@ -104,6 +157,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 +216,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; @@ -139,6 +240,26 @@ public final class Credential implements Parcelable { */ public byte[] certSha256FingerPrint = null; + /** + * Constructor for creating CertificateCredential with default values. + */ + public CertificateCredential() {} + + /** + * Copy constructor. + * + * @param source The source to copy from + */ + public CertificateCredential(CertificateCredential source) { + if (source != null) { + certType = source.certType; + if (source.certSha256FingerPrint != null) { + certSha256FingerPrint = Arrays.copyOf(source.certSha256FingerPrint, + source.certSha256FingerPrint.length); + } + } + } + @Override public int describeContents() { return 0; @@ -164,6 +285,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 +327,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; @@ -200,6 +346,23 @@ public final class Credential implements Parcelable { */ public int eapType = Integer.MIN_VALUE; + /** + * Constructor for creating SimCredential with default values. + */ + public SimCredential() {} + + /** + * Copy constructor + * + * @param source The source to copy from + */ + public SimCredential(SimCredential source) { + if (source != null) { + imsi = source.imsi; + eapType = source.eapType; + } + } + @Override public int describeContents() { return 0; @@ -225,6 +388,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 +423,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; @@ -258,6 +478,37 @@ public final class Credential implements Parcelable { */ public PrivateKey clientPrivateKey = null; + /** + * Constructor for creating Credential with default values. + */ + public Credential() {} + + /** + * Copy constructor. + * + * @param source The source to copy from + */ + public Credential(Credential source) { + if (source != null) { + realm = source.realm; + if (source.userCredential != null) { + userCredential = new UserCredential(source.userCredential); + } + if (source.certCredential != null) { + certCredential = new CertificateCredential(source.certCredential); + } + if (source.simCredential != null) { + simCredential = new SimCredential(source.simCredential); + } + if (source.clientCertificateChain != null) { + clientCertificateChain = Arrays.copyOf(source.clientCertificateChain, + source.clientCertificateChain.length); + } + caCertificate = source.caCertificate; + clientPrivateKey = source.clientPrivateKey; + } + } + @Override public int describeContents() { return 0; @@ -296,6 +547,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 +604,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 +745,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..d4a5792d93fc 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. */ @@ -50,6 +53,27 @@ public final class HomeSP implements Parcelable { */ public long[] roamingConsortiumOIs = null; + /** + * Constructor for creating HomeSP with default values. + */ + public HomeSP() {} + + /** + * Copy constructor. + * + * @param source The source to copy from + */ + public HomeSP(HomeSP source) { + if (source != null) { + fqdn = source.fqdn; + friendlyName = source.friendlyName; + if (source.roamingConsortiumOIs != null) { + roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs, + source.roamingConsortiumOIs.length); + } + } + } + @Override public int describeContents() { return 0; @@ -77,6 +101,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/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index ee2e895af537..8b1cfaee8119 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -28,5 +28,6 @@ interface IWifiP2pManager Messenger getMessenger(); Messenger getP2pStateMachineMessenger(); void setMiracastMode(int mode); + void checkConfigureWifiDisplayPermission(); } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 398308dd2427..c93ac7b5f8f1 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -1324,6 +1324,11 @@ public class WifiP2pManager { Channel c, WifiP2pWfdInfo wfdInfo, ActionListener listener) { checkChannel(c); + try { + mService.checkConfigureWifiDisplayPermission(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo); } diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 new file mode 100644 index 000000000000..8c1eb0867298 --- /dev/null +++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 @@ -0,0 +1,85 @@ +Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu +dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh +cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6 +IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n +SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo +YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn +UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi +V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ +M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM +MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth +VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt +RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD +QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD +QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx +bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1 +MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv +Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2 +ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo +YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4 +VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo +YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi +RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj +bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i +MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM +MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy +UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD +QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD +OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3 +dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0 +S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV +K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G +dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur +TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn +SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2 +WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0 +VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM +MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ +Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi +V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ +a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q +VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV +KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG +bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB +OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB +Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4 +VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs +UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn +SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2 +WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk +V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU +bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ +QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94 +LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD +UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR +VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U +bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU +azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V +VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw +TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY +TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T +dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV +RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo +U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK +ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz +M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh +CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX +TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH +U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF +YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk +MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV +akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ +MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD +amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY +ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew +OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX +MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF +MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw +aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG +S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS +a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts +RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf new file mode 100644 index 000000000000..6d86dd53eb76 --- /dev/null +++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf @@ -0,0 +1,73 @@ +Content-Type: multipart/mixed; boundary={boundary} +Content-Transfer-Encoding: base64 + +--{boundary} +Content-Type: application/x-passpoint-profile +Content-Transfer-Encoding: base64 + +PE1nbXRUcmVlIHhtbG5zPSJzeW5jbWw6ZG1kZGYxLjIiPgogIDxWZXJEVEQ+MS4yPC9WZXJEVEQ+ +CiAgPE5vZGU+CiAgICA8Tm9kZU5hbWU+UGVyUHJvdmlkZXJTdWJzY3JpcHRpb248L05vZGVOYW1l +PgogICAgPFJUUHJvcGVydGllcz4KICAgICAgPFR5cGU+CiAgICAgICAgPERERk5hbWU+dXJuOndm +YTptbzpob3RzcG90MmRvdDAtcGVycHJvdmlkZXJzdWJzY3JpcHRpb246MS4wPC9EREZOYW1lPgog +ICAgICA8L1R5cGU+CiAgICA8L1JUUHJvcGVydGllcz4KICAgIDxOb2RlPgogICAgICA8Tm9kZU5h +bWU+aTAwMTwvTm9kZU5hbWU+CiAgICAgIDxOb2RlPgogICAgICAgIDxOb2RlTmFtZT5Ib21lU1A8 +L05vZGVOYW1lPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZyaWVuZGx5TmFt +ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+Q2VudHVyeSBIb3VzZTwvVmFsdWU+CiAgICAg +ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZRRE48L05vZGVO +YW1lPgogICAgICAgICAgPFZhbHVlPm1pNi5jby51azwvVmFsdWU+CiAgICAgICAgPC9Ob2RlPgog +ICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25zb3J0aXVtT0k8L05v +ZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVlPgogICAgICAgIDwv +Tm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9kZU5hbWU+Q3JlZGVu +dGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+UmVhbG08 +L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPnNoYWtlbi5zdGlycmVkLmNvbTwvVmFsdWU+CiAg +ICAgICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlVzZXJuYW1l +UGFzc3dvcmQ8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt +ZT5Vc2VybmFtZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5qYW1lczwvVmFsdWU+CiAg +ICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1lPlBh +c3N3b3JkPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPlltOXVaREF3Tnc9PTwvVmFsdWU+ +CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l +PkVBUE1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO +b2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgICA8VmFsdWU+MjE8L1ZhbHVl +PgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO +b2RlTmFtZT5Jbm5lck1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPk1TLUNI +QVAtVjI8L1ZhbHVlPgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8L05vZGU+CiAgICAg +ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0 +aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l +PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh +bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl +TmFtZT5DZXJ0U0hBMjU2RmluZ2VyUHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+ +MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx +ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg +IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k +ZT4KICAgICAgICAgICAgPE5vZGVOYW1lPklNU0k8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFs +dWU+aW1zaTwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAg +ICAgICAgPE5vZGVOYW1lPkVBUFR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+MjQ8 +L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgog +ICAgPC9Ob2RlPgogIDwvTm9kZT4KPC9NZ210VHJlZT4K + +--{boundary} +Content-Type: application/x-x509-ca-cert +Content-Transfer-Encoding: base64 + +LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLRENDQWhDZ0F3SUJBZ0lKQUlMbEZkd3pM +VnVyTUEwR0NTcUdTSWIzRFFFQkN3VUFNQkl4RURBT0JnTlYKQkFNVEIwVkJVQ0JEUVRFd0hoY05N +VFl3TVRFeU1URTFNREUxV2hjTk1qWXdNVEE1TVRFMU1ERTFXakFTTVJBdwpEZ1lEVlFRREV3ZEZR +VkFnUTBFeE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnpuQVBV +ejI2TXNhZTR3czQzY3pSNDEvSjJRdHJTSVpVS21WVXNWdW1EYllIclBOdlRYS1NNWEFjZXdPUkRR +WVgKUnF2SHZwbjhDc2NCMStvR1hadkh3eGo0elYwV0tvSzJ6ZVhrYXUzdmN5bDNISUt1cEpmcTJU +RUFDZWZWamowdApKVytYMzVQR1dwOS9INXpJVU5WTlZqUzdVbXM4NEl2S2hSQjg1MTJQQjlVeUhh +Z1hZVlg1R1dwQWNWcHlmcmxSCkZJOVFkaGgrUGJrMHV5a3RkYmYvQ2RmZ0hPb2ViclR0d1Jsak0w +b0R0WCsyQ3Y2ajB3Qks3aEQ4cFB2ZjErdXkKR3pjemlnQVUvNEt3N2VacXlkZjlCKzVSdXBSK0la +aXBYNDF4RWlJcktSd3FpNTE3V1d6WGNqYUcyY05iZjQ1MQp4cEg1UG5WM2kxdHEwNGpNR1FVekZ3 +SURBUUFCbzRHQU1INHdIUVlEVlIwT0JCWUVGSXdYNHZzOEJpQmNTY29kCjVub1pIUk04RTQraU1F +SUdBMVVkSXdRN01EbUFGSXdYNHZzOEJpQmNTY29kNW5vWkhSTThFNCtpb1Jha0ZEQVMKTVJBd0Rn +WURWUVFERXdkRlFWQWdRMEV4Z2drQWd1VVYzRE10VzZzd0RBWURWUjBUQkFVd0F3RUIvekFMQmdO +VgpIUThFQkFNQ0FRWXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRmZRcU9UQTdSdjdLK2x1UTdw +bmFzNEJZd0hFCjlHRVAvdW9odjZLT3kwVEdRRmJyUlRqRm9MVk5COUJaMXltTURaMC9USXdJVWM3 +d2k3YTh0NW1FcVlIMTUzd1cKYVdvb2lTanlMTGh1STRzTnJOQ090aXNkQnEycjJNRlh0NmgwbUFR +WU9QdjhSOEs3L2ZnU3hHRnF6aHlObW1WTAoxcUJKbGR4MzRTcHdzVEFMUVZQYjRoR3dKelpmcjFQ +Y3BFUXg2eE1uVGw4eEVXWkUzTXM5OXVhVXhiUXFJd1J1CkxnQU9rTkNtWTJtODlWaHphSEoxdVY4 +NUFkTS90RCtZc21sbm5qdDlMUkNlamJCaXBqSUdqT1hyZzFKUCtseFYKbXVNNHZIK1AvbWxteHNQ +UHowZDY1YitFR21KWnBvTGtPL3RkTk52Q1l6akpwVEVXcEVzTzZOTWhLWW89Ci0tLS0tRU5EIENF +UlRJRklDQVRFLS0tLS0K +--{boundary}-- diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 new file mode 100644 index 000000000000..906bfb397464 --- /dev/null +++ b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 @@ -0,0 +1,85 @@ +Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu +dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh +cHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJvZmlsZQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBi +YXNlNjQKClBFMW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lE +eFdaWEpFVkVRK01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJX +VStVR1Z5VUhKdmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BG +SlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldV +K2RYSnVPbmRtCllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNK +cGNIUnBiMjQ2TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFK +VVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRB +d01Ud3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0 +WlQ1SWIyMWxVMUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn +SUNBZ1BFNXZaR1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn +SUNBZ0lDQThWbUZzZFdVK1EyVnVkSFZ5ZVNCSWIzVnpaVHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0Fn +UEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ +a1pSUkU0OEwwNXZaR1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbTFwTmk1amJ5NTFh +end2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2cKSUNBZ0lDQWdJRHhPYjJSbFBnb2dJ +Q0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6YjNKMGFYVnRUMGs4TDA1dgpa +R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFOalk4TDFaaGJI +VmxQZ29nSUNBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBOFRt +OWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpHVnUKZEdsaGJEd3ZUbTlrWlU1aGJX +VStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStVbVZoYkcw +OApMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbk5vWVd0bGJpNXpkR2x5Y21W +a0xtTnZiVHd2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS +bFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWwKVUdGemMzZHZjbVE4TDA1 +dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJs +VG1GdApaVDVWYzJWeWJtRnRaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx +WlQ1cVlXMWxjend2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0Fn +SUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsQmgKYzNOM2IzSmtQQzlP +YjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGxsdE9YVmFSRUYzVG5jOVBUd3ZW +bUZzZFdVKwpDaUFnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJ +Q0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsClBrVkJVRTFsZEdodlpEd3ZUbTlrWlU1aGJXVStD +aUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRa +VDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVK01q +RThMMVpoYkhWbApQZ29nSUNBZ0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lE +eE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhPCmIyUmxUbUZ0WlQ1SmJtNWxjazFsZEdodlpE +d3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGsxVExVTkkKUVZBdFZq +SThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4TDA1 +dlpHVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNB +Z0lDQWdQRTV2WkdWT1lXMWxQa1JwWjJsMFlXeERaWEowCmFXWnBZMkYwWlR3dlRtOWtaVTVoYldV +K0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtO +bGNuUnBabWxqWVhSbFZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx +WlQ1NE5UQTVkak04TDFaaApiSFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0Fn +SUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVEWlhKMFUwaEJNalUy +Um1sdVoyVnlVSEpwYm5ROEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSsK +TVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1N +V1l4WmpGbU1XWXhaakZtTVdZeApaakZtTVdZeFpqd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lDQThM +MDV2WkdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnCklEeE9iMlJsUGdvZ0lDQWdJ +Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBsTkpUVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFRt +OWsKWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQa2xOVTBrOEwwNXZaR1ZPWVcxbFBn +b2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1GcwpkV1UrYVcxemFUd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lD +QThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnCklDQWdJQ0FnUEU1dlpH +Vk9ZVzFsUGtWQlVGUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV +K01qUTgKTDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05 +a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnUEM5T2IyUmxQZ29nSUR3dlRtOWtaVDRLUEM5 +TloyMTBWSEpsWlQ0SwoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC14 +NTA5LWNhLWNlcnQKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgpMUzB0TFMxQ1JV +ZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSTFJFTkRRV2hEWjBGM1NVSkJaMGxLUVVs +TWJFWmtkM3BNClZuVnlUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOUWtsNFJVUkJUMEpuVGxZ +S1FrRk5WRUl3VmtKVlEwSkVVVlJGZDBob1kwNU4KVkZsM1RWUkZlVTFVUlRGTlJFVXhWMmhqVGsx +cVdYZE5WRUUxVFZSRk1VMUVSVEZYYWtGVFRWSkJkd3BFWjFsRVZsRlJSRVYzWkVaUgpWa0ZuVVRC +RmVFMUpTVUpKYWtGT1FtZHJjV2hyYVVjNWR6QkNRVkZGUmtGQlQwTkJVVGhCVFVsSlFrTm5TME5C +VVVWQkNucHVRVkJWCmVqSTJUWE5oWlRSM2N6UXpZM3BTTkRFdlNqSlJkSEpUU1ZwVlMyMVdWWE5X +ZFcxRVlsbEljbEJPZGxSWVMxTk5XRUZqWlhkUFVrUlIKV1ZnS1VuRjJTSFp3YmpoRGMyTkNNU3R2 +UjFoYWRraDNlR28wZWxZd1YwdHZTeko2WlZocllYVXpkbU41YkROSVNVdDFjRXBtY1RKVQpSVUZE +WldaV2Ftb3dkQXBLVnl0WU16VlFSMWR3T1M5SU5YcEpWVTVXVGxacVV6ZFZiWE00TkVsMlMyaFNR +amcxTVRKUVFqbFZlVWhoCloxaFpWbGcxUjFkd1FXTldjSGxtY214U0NrWkpPVkZrYUdnclVHSnJN +SFY1YTNSa1ltWXZRMlJtWjBoUGIyVmljbFIwZDFKc2FrMHcKYjBSMFdDc3lRM1kyYWpCM1FrczNh +RVE0Y0ZCMlpqRXJkWGtLUjNwamVtbG5RVlV2TkV0M04yVmFjWGxrWmpsQ0t6VlNkWEJTSzBsYQph +WEJZTkRGNFJXbEpja3RTZDNGcE5URTNWMWQ2V0dOcVlVY3lZMDVpWmpRMU1RcDRjRWcxVUc1V00y +a3hkSEV3TkdwTlIxRlZla1ozClNVUkJVVUZDYnpSSFFVMUlOSGRJVVZsRVZsSXdUMEpDV1VWR1NY +ZFlOSFp6T0VKcFFtTlRZMjlrQ2pWdWIxcElVazA0UlRRcmFVMUYKU1VkQk1WVmtTWGRSTjAxRWJV +RkdTWGRZTkhaek9FSnBRbU5UWTI5a05XNXZXa2hTVFRoRk5DdHBiMUpoYTBaRVFWTUtUVkpCZDBS +bgpXVVJXVVZGRVJYZGtSbEZXUVdkUk1FVjRaMmRyUVdkMVZWWXpSRTEwVnpaemQwUkJXVVJXVWpC +VVFrRlZkMEYzUlVJdmVrRk1RbWRPClZncElVVGhGUWtGTlEwRlJXWGRFVVZsS1MyOWFTV2gyWTA1 +QlVVVk1RbEZCUkdkblJVSkJSbVpSY1U5VVFUZFNkamRMSzJ4MVVUZHcKYm1Gek5FSlpkMGhGQ2ps +SFJWQXZkVzlvZGpaTFQza3dWRWRSUm1KeVVsUnFSbTlNVms1Q09VSmFNWGx0VFVSYU1DOVVTWGRK +VldNMwpkMmszWVRoME5XMUZjVmxJTVRVemQxY0tZVmR2YjJsVGFubE1UR2gxU1RSelRuSk9RMDkw +YVhOa1FuRXljakpOUmxoME5tZ3diVUZSCldVOVFkamhTT0VzM0wyWm5VM2hIUm5GNmFIbE9iVzFX +VEFveGNVSktiR1I0TXpSVGNIZHpWRUZNVVZaUVlqUm9SM2RLZWxwbWNqRlEKWTNCRlVYZzJlRTF1 +Vkd3NGVFVlhXa1V6VFhNNU9YVmhWWGhpVVhGSmQxSjFDa3huUVU5clRrTnRXVEp0T0RsV2FIcGhT +RW94ZFZZNApOVUZrVFM5MFJDdFpjMjFzYm01cWREbE1Va05sYW1KQ2FYQnFTVWRxVDFoeVp6RktV +Q3RzZUZZS2JYVk5OSFpJSzFBdmJXeHRlSE5RClVIb3daRFkxWWl0RlIyMUtXbkJ2VEd0UEwzUmtU +azUyUTFsNmFrcHdWRVZYY0VWelR6Wk9UV2hMV1c4OUNpMHRMUzB0UlU1RUlFTkYKVWxSSlJrbERR +VlJGTFMwdExTMEsKLS17Ym91bmRhcnl9LS0K diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 new file mode 100644 index 000000000000..3fa97d1cdd76 --- /dev/null +++ b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 @@ -0,0 +1,85 @@ +Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu +dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh +cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6 +IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n +SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo +YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn +UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi +V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ +M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM +MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth +VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt +RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD +QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD +QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx +bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1 +MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv +Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2 +ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo +YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4 +VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo +YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi +RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj +bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i +MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM +MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy +UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD +QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD +OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3 +dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0 +S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV +K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G +dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur +TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn +SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2 +WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0 +VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM +MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ +Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi +V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ +a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q +VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV +KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG +bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB +OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB +Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4 +VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs +UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn +SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2 +WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk +V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU +bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ +QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94 +LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD +UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR +VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U +bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU +azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V +VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw +TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY +TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T +dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV +RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo +U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK +ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz +M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh +CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX +TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH +U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF +YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk +MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV +akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ +MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD +amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY +ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew +OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX +MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF +MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw +aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG +S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS +a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts +RFFWUkZMUzB0TFMwSwo= diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 new file mode 100644 index 000000000000..975f8e539cc3 --- /dev/null +++ b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 @@ -0,0 +1,85 @@ +Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu +dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTMyCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh +cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6 +IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n +SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo +YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn +UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi +V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ +M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM +MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth +VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt +RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD +QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD +QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx +bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1 +MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv +Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2 +ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo +YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4 +VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo +YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi +RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj +bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i +MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM +MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy +UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD +QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD +OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3 +dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0 +S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV +K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G +dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur +TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn +SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2 +WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0 +VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM +MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ +Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi +V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ +a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX +eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD +QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q +VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV +KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG +bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB +OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB +Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4 +VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs +UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn +SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2 +WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk +V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU +bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ +QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94 +LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD +UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR +VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U +bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU +azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V +VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw +TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY +TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T +dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV +RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo +U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK +ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz +M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh +CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX +TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH +U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF +YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk +MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV +akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ +MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD +amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY +ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew +OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX +MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF +MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw +aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG +S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS +a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts +RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64 new file mode 100644 index 000000000000..833c52751b95 --- /dev/null +++ b/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64 @@ -0,0 +1,31 @@ +Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu +dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh +cHBsaWNhdGlvbi94LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNl +NjQKCkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERa +MEYzU1VKQlowbEtRVWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5R +a2w0UlVSQlQwSm5UbFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVS +VEZOUkVVeFYyaGpUazFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJF +VjNaRVpSClZrRm5VVEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVU +aEJUVWxKUWtOblMwTkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRI +SlRTVnBWUzIxV1ZYTldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNI +WndiamhEYzJOQ01TdHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0 +MWNFcG1jVEpVClJVRkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpk +VmJYTTRORWwyUzJoU1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2ta +Sk9WRmthR2dyVUdKck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0Nz +eVEzWTJhakIzUWtzM2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxD +S3pWU2RYQlNLMGxhCmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalEx +TVFwNGNFZzFVRzVXTTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxF +VmxJd1QwSkNXVVZHU1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRC +TVZWa1NYZFJOMDFFYlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhh +MFpFUVZNS1RWSkJkMFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBW +elp6ZDBSQldVUldVakJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVV +VmxLUzI5YVNXaDJZMDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpi +bUZ6TkVKWmQwaEZDamxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1Y +bHRUVVJhTUM5VVNYZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRH +aDFTVFJ6VG5KT1EwOTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUz +aEhSbkY2YUhsT2JXMVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pG +UQpZM0JGVVhnMmVFMXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtO +dFdUSnRPRGxXYUhwaFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhC +cVNVZHFUMWh5WnpGS1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIx +S1duQnZUR3RQTDNSa1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVF +SUVORgpVbFJKUmtsRFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo= diff --git a/wifi/tests/assets/hsr1/README.txt b/wifi/tests/assets/hsr1/README.txt new file mode 100644 index 000000000000..d1f8384fc979 --- /dev/null +++ b/wifi/tests/assets/hsr1/README.txt @@ -0,0 +1,5 @@ +HSR1ProfileWithCACert.conf - unencoded installation file that contains a Passpoint profile and a CA Certificate +HSR1ProfileWithCACert.base64 - base64 encoded of the data contained in HSR1ProfileWithCAWith.conf +HSR1ProfileWithNonBase64Part.base64 - base64 encoded installation file that contains a part of non-base64 encoding type +HSR1ProfileWithMissingBoundary.base64 - base64 encoded installation file with missing end-boundary in the MIME data +HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type. diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java new file mode 100644 index 000000000000..6095929758f0 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java @@ -0,0 +1,197 @@ +/* + * 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.hotspot2; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.wifi.FakeKeys; +import android.net.wifi.hotspot2.pps.Credential; +import android.net.wifi.hotspot2.pps.HomeSP; +import android.test.suitebuilder.annotation.SmallTest; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.hotspot2.ConfigBuilder}. + */ +@SmallTest +public class ConfigBuilderTest { + /** + * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a + * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}. + */ + private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = + "assets/hsr1/HSR1ProfileWithCACert.base64"; + private static final String PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA = + "assets/hsr1/HSR1ProfileWithCACert.conf"; + private static final String PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART = + "assets/hsr1/HSR1ProfileWithNonBase64Part.base64"; + private static final String PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY = + "assets/hsr1/HSR1ProfileWithMissingBoundary.base64"; + private static final String PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE = + "assets/hsr1/HSR1ProfileWithInvalidContentType.base64"; + private static final String PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE = + "assets/hsr1/HSR1ProfileWithoutProfile.base64"; + + /** + * Read the content of the given resource file into a String. + * + * @param filename String name of the file + * @return String + * @throws IOException + */ + private String loadResourceFile(String filename) throws IOException { + InputStream in = getClass().getClassLoader().getResourceAsStream(filename); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append("\n"); + } + + return builder.toString(); + } + + /** + * Generate a {@link PasspointConfiguration} that matches the configuration specified in the + * XML file {@link #PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT}. + * + * @return {@link PasspointConfiguration} + */ + private PasspointConfiguration generateConfigurationFromProfile() { + PasspointConfiguration config = new PasspointConfiguration(); + + // HomeSP configuration. + config.homeSp = new HomeSP(); + config.homeSp.friendlyName = "Century House"; + config.homeSp.fqdn = "mi6.co.uk"; + config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L}; + + // Credential configuration. + config.credential = new Credential(); + config.credential.realm = "shaken.stirred.com"; + config.credential.userCredential = new Credential.UserCredential(); + config.credential.userCredential.username = "james"; + config.credential.userCredential.password = "Ym9uZDAwNw=="; + config.credential.userCredential.eapType = 21; + config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2"; + config.credential.certCredential = new Credential.CertificateCredential(); + config.credential.certCredential.certType = "x509v3"; + config.credential.certCredential.certSha256FingerPrint = new byte[32]; + Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f); + config.credential.simCredential = new Credential.SimCredential(); + config.credential.simCredential.imsi = "imsi"; + config.credential.simCredential.eapType = 24; + config.credential.caCertificate = FakeKeys.CA_CERT0; + return config; + } + + /** + * Verify a valid installation file is parsed successfully with the matching contents. + * + * @throws Exception + */ + @Test + public void parseConfigFile() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); + PasspointConfiguration expectedConfig = generateConfigurationFromProfile(); + PasspointConfiguration actualConfig = + ConfigBuilder.buildPasspointConfig( + "application/x-wifi-config", configStr.getBytes()); + assertTrue(actualConfig.equals(expectedConfig)); + } + + /** + * Verify that parsing an installation file with invalid MIME type will fail. + * + * @throws Exception + */ + @Test + public void parseConfigFileWithInvalidMimeType() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); + assertNull(ConfigBuilder.buildPasspointConfig( + "application/wifi-config", configStr.getBytes())); + } + + /** + * Verify that parsing an un-encoded installation file will fail. + * + * @throws Exception + */ + @Test + public void parseConfigFileWithUnencodedData() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA); + assertNull(ConfigBuilder.buildPasspointConfig( + "application/x-wifi-config", configStr.getBytes())); + } + + /** + * Verify that parsing an installation file that contains a non-base64 part will fail. + * + * @throws Exception + */ + @Test + public void parseConfigFileWithInvalidPart() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART); + assertNull(ConfigBuilder.buildPasspointConfig( + "application/x-wifi-config", configStr.getBytes())); + } + + /** + * Verify that parsing an installation file that contains a missing boundary string will fail. + * + * @throws Exception + */ + @Test + public void parseConfigFileWithMissingBoundary() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY); + assertNull(ConfigBuilder.buildPasspointConfig( + "application/x-wifi-config", configStr.getBytes())); + } + + /** + * Verify that parsing an installation file that contains a MIME part with an invalid content + * type will fail. + * + * @throws Exception + */ + @Test + public void parseConfigFileWithInvalidContentType() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE); + assertNull(ConfigBuilder.buildPasspointConfig( + "application/x-wifi-config", configStr.getBytes())); + } + + /** + * Verify that parsing an installation file that doesn't contain a Passpoint profile will fail. + * + * @throws Exception + */ + @Test + public void parseConfigFileWithoutPasspointProfile() throws Exception { + String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE); + assertNull(ConfigBuilder.buildPasspointConfig( + "application/x-wifi-config", configStr.getBytes())); + } +}
\ No newline at end of file diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index be11f0ee64c0..2350d3201171 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; @@ -31,6 +33,11 @@ import org.junit.Test; @SmallTest public class PasspointConfigurationTest { + /** + * Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}. + * + * @return {@link android.net.wifi.hotspot2.pps.HomeSP} + */ private static HomeSP createHomeSp() { HomeSP homeSp = new HomeSP(); homeSp.fqdn = "fqdn"; @@ -39,18 +46,31 @@ public class PasspointConfigurationTest { return homeSp; } + /** + * Utility function for creating a {@link android.net.wifi.hotspot2.pps.Credential}. + * + * @return {@link android.net.wifi.hotspot2.pps.Credential} + */ private static Credential createCredential() { Credential cred = new Credential(); 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; return cred; } + /** + * Verify parcel write and read consistency for the given configuration. + * + * @param writeConfig The configuration to verify + * @throws Exception + */ private static void verifyParcel(PasspointConfiguration writeConfig) throws Exception { Parcel parcel = Parcel.obtain(); writeConfig.writeToParcel(parcel, 0); @@ -61,11 +81,21 @@ 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 +104,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 +116,89 @@ 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); } -}
\ No newline at end of file + + /** + * 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()); + } + + /** + * Verify that copy constructor works when pass in a null source. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorWithNullSource() throws Exception { + PasspointConfiguration copyConfig = new PasspointConfiguration(null); + PasspointConfiguration defaultConfig = new PasspointConfiguration(); + assertTrue(copyConfig.equals(defaultConfig)); + } + + /** + * Verify that copy constructor works when pass in a valid source. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorWithValidSource() throws Exception { + PasspointConfiguration sourceConfig = new PasspointConfiguration(); + sourceConfig.homeSp = createHomeSp(); + sourceConfig.credential = createCredential(); + PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig); + assertTrue(copyConfig.equals(sourceConfig)); + } +} 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..9c8b749e1c93 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,434 @@ 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()); + } + + /** + * Verify that copy constructor works when pass in a null source. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorWithNullSource() throws Exception { + Credential copyCred = new Credential(null); + Credential defaultCred = new Credential(); + assertTrue(copyCred.equals(defaultCred)); + } + + /** + * Verify that copy constructor works when pass in a source with user credential. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorWithSourceWithUserCred() throws Exception { + Credential sourceCred = createCredentialWithUserCredential(); + Credential copyCred = new Credential(sourceCred); + assertTrue(copyCred.equals(sourceCred)); + } + + /** + * Verify that copy constructor works when pass in a source with certificate credential. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorWithSourceWithCertCred() throws Exception { + Credential sourceCred = createCredentialWithCertificateCredential(); + Credential copyCred = new Credential(sourceCred); + assertTrue(copyCred.equals(sourceCred)); + } + + /** + * Verify that copy constructor works when pass in a source with SIM credential. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorWithSourceWithSimCred() throws Exception { + Credential sourceCred = createCredentialWithSimCredential(); + Credential copyCred = new Credential(sourceCred); + assertTrue(copyCred.equals(sourceCred)); + } +}
\ 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..c70799332b02 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,103 @@ 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()); + } + + /** + * Verify that copy constructor works when pass in a null source. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorFromNullSource() throws Exception { + HomeSP copySp = new HomeSP(null); + HomeSP defaultSp = new HomeSP(); + assertTrue(copySp.equals(defaultSp)); + } + + /** + * Verify that copy constructor works when pass in a valid source. + * + * @throws Exception + */ + @Test + public void validateCopyConstructorFromValidSource() throws Exception { + HomeSP sourceSp = new HomeSP(); + sourceSp.fqdn = "fqdn"; + sourceSp.friendlyName = "friendlyName"; + sourceSp.roamingConsortiumOIs = new long[] {0x55, 0x66}; + HomeSP copySp = new HomeSP(sourceSp); + assertTrue(copySp.equals(sourceSp)); + } } |