Merge "Revert "Move Resource creation out of ContextImpl constructor""
diff --git a/Android.mk b/Android.mk
index 6f96803..552103d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -245,12 +245,15 @@
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 @@
../../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_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 cee8fdb..71e6af7 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -241,6 +241,7 @@
$(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 0000000..4d68018
--- /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 5503ca9..990be24 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 @@
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 88cb8e6..f56c763 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 @@
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 @@
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 fd393e9..bb9dc4a 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 @@
// 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 22871fa..9d93eeb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18,6 +18,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.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.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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 a8a725e..e887464 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -28,6 +28,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 50dfa2a..0a76d78 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -18,6 +18,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.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.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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 470a0fa..f003061 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 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 @@
@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 132a4f8..63641a8 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 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 31c7421..3ac70d6 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 @@
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 0000000..76766c7
--- /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 0000000..c963b23
--- /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 0000000..1e426d6
--- /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 718f141..50f46f4 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 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 @@
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 d527ad7..4291c77 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.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 @@
public final class Sm {
private static final String TAG = "Sm";
- IMountService mSm;
+ IStorageManager mSm;
private String[] mArgs;
private int mNextArg;
@@ -55,7 +55,7 @@
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 8681166..32b4595 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 @@
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 ddeb8e7..d98b4ff 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 @@
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 @@
* @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 8428e41..f09bad9 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -174,9 +174,6 @@
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.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$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 aed7a36..8c71f50 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -18,7 +18,7 @@
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 @@
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 0000000..d3e9f08
--- /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 0552d34..58f5a78 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1494,22 +1494,22 @@
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 b3e2f57..64e5dfc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -53,7 +53,6 @@
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.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.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.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 @@
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 @@
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 boolean isVoiceInteractionRoot() {
try {
return mVoiceInteractor != null
- && ActivityManagerNative.getDefault().isRootVoiceInteraction(mToken);
+ && ActivityManager.getService().isRootVoiceInteraction(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1329,7 +1336,7 @@
*/
public boolean isLocalVoiceInteractionSupported() {
try {
- return ActivityManagerNative.getDefault().supportsLocalVoiceInteraction();
+ return ActivityManager.getService().supportsLocalVoiceInteraction();
} catch (RemoteException re) {
}
return false;
@@ -1343,7 +1350,7 @@
*/
public void startLocalVoiceInteraction(Bundle privateOptions) {
try {
- ActivityManagerNative.getDefault().startLocalVoiceInteraction(mToken, privateOptions);
+ ActivityManager.getService().startLocalVoiceInteraction(mToken, privateOptions);
} catch (RemoteException re) {
}
}
@@ -1372,7 +1379,7 @@
*/
public void stopLocalVoiceInteraction() {
try {
- ActivityManagerNative.getDefault().stopLocalVoiceInteraction(mToken);
+ ActivityManager.getService().stopLocalVoiceInteraction(mToken);
} catch (RemoteException re) {
}
}
@@ -1688,6 +1695,53 @@
}
/**
+ * 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 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 @@
if (mDoReportFullyDrawn) {
mDoReportFullyDrawn = false;
try {
- ActivityManagerNative.getDefault().reportActivityFullyDrawn(mToken);
+ ActivityManager.getService().reportActivityFullyDrawn(mToken);
} catch (RemoteException e) {
}
}
@@ -1886,7 +1940,7 @@
*/
public boolean isInMultiWindowMode() {
try {
- return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken);
+ return ActivityManager.getService().isInMultiWindowMode(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1911,7 +1965,7 @@
*/
public boolean isInPictureInPictureMode() {
try {
- return ActivityManagerNative.getDefault().isInPictureInPictureMode(mToken);
+ return ActivityManager.getService().isInPictureInPictureMode(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1923,7 +1977,33 @@
*/
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 @@
*/
@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 @@
*/
@Override
public int getWindowStackId() throws RemoteException {
- return ActivityManagerNative.getDefault().getActivityStackId(mToken);
+ return ActivityManager.getService().getActivityStackId(mToken);
}
/**
@@ -4453,7 +4533,7 @@
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 @@
}
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 @@
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 void overridePendingTransition(int enterAnim, int exitAnim) {
try {
- ActivityManagerNative.getDefault().overridePendingTransition(
+ ActivityManager.getService().overridePendingTransition(
mToken, getPackageName(), enterAnim, exitAnim);
} catch (RemoteException e) {
}
@@ -5077,7 +5157,7 @@
@Nullable
public String getCallingPackage() {
try {
- return ActivityManagerNative.getDefault().getCallingPackage(mToken);
+ return ActivityManager.getService().getCallingPackage(mToken);
} catch (RemoteException e) {
return null;
}
@@ -5100,7 +5180,7 @@
@Nullable
public ComponentName getCallingActivity() {
try {
- return ActivityManagerNative.getDefault().getCallingActivity(mToken);
+ return ActivityManager.getService().getCallingActivity(mToken);
} catch (RemoteException e) {
return null;
}
@@ -5185,7 +5265,7 @@
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 @@
if (resultData != null) {
resultData.prepareToLeaveProcess(this);
}
- if (ActivityManagerNative.getDefault()
+ if (ActivityManager.getService()
.finishActivity(mToken, resultCode, resultData, finishTask)) {
mFinished = true;
}
@@ -5250,7 +5330,7 @@
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 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 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 boolean releaseInstance() {
try {
- return ActivityManagerNative.getDefault().releaseActivityInstance(mToken);
+ return ActivityManager.getService().releaseActivityInstance(mToken);
} catch (RemoteException e) {
// Empty
}
@@ -5434,7 +5514,7 @@
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 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 int getRequestedOrientation() {
if (mParent == null) {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getRequestedOrientation(mToken);
} catch (RemoteException e) {
// Empty
@@ -5501,7 +5581,7 @@
*/
public int getTaskId() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getTaskForActivity(mToken, false);
} catch (RemoteException e) {
return -1;
@@ -5516,7 +5596,7 @@
*/
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 boolean moveTaskToBack(boolean nonRoot) {
try {
- return ActivityManagerNative.getDefault().moveActivityTaskToBack(
+ return ActivityManager.getService().moveActivityTaskToBack(
mToken, nonRoot);
} catch (RemoteException e) {
// Empty
@@ -5706,7 +5786,7 @@
}
}
try {
- ActivityManagerNative.getDefault().setTaskDescription(mToken, mTaskDescription);
+ ActivityManager.getService().setTaskDescription(mToken, mTaskDescription);
} catch (RemoteException e) {
}
}
@@ -5948,6 +6028,11 @@
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 boolean isImmersive() {
try {
- return ActivityManagerNative.getDefault().isImmersive(mToken);
+ return ActivityManager.getService().isImmersive(mToken);
} catch (RemoteException e) {
return false;
}
@@ -5982,7 +6067,7 @@
return false;
}
try {
- return ActivityManagerNative.getDefault().isTopOfTask(getActivityToken());
+ return ActivityManager.getService().isTopOfTask(getActivityToken());
} catch (RemoteException e) {
return false;
}
@@ -6008,7 +6093,7 @@
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 @@
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 @@
ActivityOptions getActivityOptions() {
try {
return ActivityOptions.fromBundle(
- ActivityManagerNative.getDefault().getActivityOptions(mToken));
+ ActivityManager.getService().getActivityOptions(mToken));
} catch (RemoteException e) {
}
return null;
@@ -6137,7 +6222,7 @@
visible = false;
}
try {
- mVisibleBehind = ActivityManagerNative.getDefault()
+ mVisibleBehind = ActivityManager.getService()
.requestVisibleBehind(mToken, visible) && visible;
} catch (RemoteException e) {
mVisibleBehind = false;
@@ -6178,7 +6263,7 @@
@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 void setImmersive(boolean i) {
try {
- ActivityManagerNative.getDefault().setImmersive(mToken, i);
+ ActivityManager.getService().setImmersive(mToken, i);
} catch (RemoteException e) {
// pass
}
@@ -6299,7 +6384,7 @@
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 @@
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 @@
}
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 void startLockTask() {
try {
- ActivityManagerNative.getDefault().startLockTaskModeByToken(mToken);
+ ActivityManager.getService().startLockTaskModeByToken(mToken);
} catch (RemoteException e) {
}
}
@@ -7013,7 +7098,7 @@
*/
public void stopLockTask() {
try {
- ActivityManagerNative.getDefault().stopLockTaskMode();
+ ActivityManager.getService().stopLockTaskMode();
} catch (RemoteException e) {
}
}
@@ -7025,7 +7110,7 @@
*/
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 9af7d8b..65f74d1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -36,6 +36,7 @@
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 @@
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 @@
}
@Override
- public void onUidIdle(int uid) {
+ public void onUidIdle(int uid, boolean disabled) {
}
}
@@ -380,8 +368,8 @@
/** @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 @@
/** @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 @@
/** @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 @@
/** @hide */
public int getFrontActivityScreenCompatMode() {
try {
- return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode();
+ return getService().getFrontActivityScreenCompatMode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -844,7 +838,7 @@
/** @hide */
public void setFrontActivityScreenCompatMode(int mode) {
try {
- ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode);
+ getService().setFrontActivityScreenCompatMode(mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -853,7 +847,7 @@
/** @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 @@
/** @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 @@
/** @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 @@
/** @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 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 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 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 @@
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 @@
private void ensureAppTaskThumbnailSizeLocked() {
if (mAppTaskThumbnailSize == null) {
try {
- mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize();
+ mAppTaskThumbnailSize = getService().getAppTaskThumbnailSize();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1825,7 +1819,7 @@
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 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 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 @@
/** @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 @@
/** @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 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 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 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 void getMemoryInfo(MemoryInfo outInfo) {
try {
- ActivityManagerNative.getDefault().getMemoryInfo(outInfo);
+ getService().getMemoryInfo(outInfo);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2554,7 +2548,7 @@
*/
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 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 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 List<ProcessErrorStateInfo> getProcessesInErrorState() {
try {
- return ActivityManagerNative.getDefault().getProcessesInErrorState();
+ return getService().getProcessesInErrorState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2890,6 +2884,29 @@
}
}
+ /** @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 List<ApplicationInfo> getRunningExternalApplications() {
try {
- return ActivityManagerNative.getDefault().getRunningExternalApplications();
+ return getService().getRunningExternalApplications();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3057,7 +3074,7 @@
*/
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 List<RunningAppProcessInfo> getRunningAppProcesses() {
try {
- return ActivityManagerNative.getDefault().getRunningAppProcesses();
+ return getService().getRunningAppProcesses();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3146,10 +3163,12 @@
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 @@
*/
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 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 void killBackgroundProcesses(String packageName) {
try {
- ActivityManagerNative.getDefault().killBackgroundProcesses(packageName,
+ getService().killBackgroundProcesses(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3262,7 +3281,7 @@
@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 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 ConfigurationInfo getDeviceConfigurationInfo() {
try {
- return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
+ return getService().getDeviceConfigurationInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3399,7 +3418,7 @@
*/
public static boolean isUserAMonkey() {
try {
- return ActivityManagerNative.getDefault().isUserAMonkey();
+ return getService().isUserAMonkey();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3521,7 +3540,7 @@
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 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 boolean switchUser(int userid) {
try {
- return ActivityManagerNative.getDefault().switchUser(userid);
+ return getService().switchUser(userid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3564,8 +3583,8 @@
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 @@
* 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 @@
/** {@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 @@
/**
* @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 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 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 void startLockTaskMode(int taskId) {
try {
- ActivityManagerNative.getDefault().startLockTaskModeById(taskId);
+ getService().startLockTaskModeById(taskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3797,7 +3833,7 @@
*/
public void stopLockTaskMode() {
try {
- ActivityManagerNative.getDefault().stopLockTaskMode();
+ getService().stopLockTaskMode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3825,7 +3861,7 @@
*/
public int getLockTaskModeState() {
try {
- return ActivityManagerNative.getDefault().getLockTaskModeState();
+ return getService().getLockTaskModeState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3843,7 +3879,7 @@
*/
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 e56fe0f..bfa6d34 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -61,6 +61,11 @@
*/
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 @@
* @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 10f0425..c09403c 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 @@
* @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 @@
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 d9a4690..1e7f4f0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -18,6 +18,7 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ /**
+ * 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 @@
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 3e8d90b..f052bf7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -80,9 +80,16 @@
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 @@
}
@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 @@
}
if (a != null) {
mNewActivities = null;
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
ActivityClientRecord prev;
do {
if (localLOGV) Slog.v(
@@ -2705,7 +2723,7 @@
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 @@
} 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 @@
}
}
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 @@
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 @@
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());
+ }
}
- r.activity.onProvideAssistContent(content);
+ if (!forAutofill) {
+ 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 @@
}
}
try {
- ActivityManagerNative.getDefault().backgroundResourcesReleased(token);
+ ActivityManager.getService().backgroundResourcesReleased(token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3044,7 +3080,7 @@
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
- IActivityManager mgr = ActivityManagerNative.getDefault();
+ IActivityManager mgr = ActivityManager.getService();
BroadcastReceiver receiver;
try {
@@ -3170,7 +3206,7 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
}
if (finishing) {
try {
- ActivityManagerNative.getDefault().activityDestroyed(token);
+ ActivityManager.getService().activityDestroyed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -4361,7 +4397,7 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
}
/*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 @@
}
try {
- ActivityManagerNative.getDefault().publishContentProviders(
+ ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
@@ -5521,7 +5564,7 @@
// 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 @@
+ 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
retHolder = prc.holder;
}
}
-
return retHolder;
}
@@ -5988,7 +6047,7 @@
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 ec21882..af41db0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -37,6 +37,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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 60046b5..f2616ff 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -22,9 +22,10 @@
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 @@
}
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 cada1b8..29b83dc 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -152,7 +152,7 @@
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 e0d0d8d..b5cbeeb 100644
--- a/core/java/android/app/AppImportanceMonitor.java
+++ b/core/java/android/app/AppImportanceMonitor.java
@@ -86,7 +86,7 @@
};
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 191cc49..ba6bc15 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -240,7 +240,9 @@
/** @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 @@
OP_TURN_SCREEN_ON,
OP_GET_ACCOUNTS,
OP_RUN_IN_BACKGROUND,
+ OP_AUDIO_ACCESSIBILITY_VOLUME,
};
/**
@@ -523,6 +526,7 @@
null,
OPSTR_GET_ACCOUNTS,
null,
+ null, // OP_AUDIO_ACCESSIBILITY_VOLUME
};
/**
@@ -594,6 +598,7 @@
"TURN_ON_SCREEN",
"GET_ACCOUNTS",
"RUN_IN_BACKGROUND",
+ "AUDIO_ACCESSIBILITY_VOLUME",
};
/**
@@ -665,6 +670,7 @@
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 @@
null, // TURN_ON_SCREEN
null, // GET_ACCOUNTS
null, // RUN_IN_BACKGROUND
+ UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME
};
/**
@@ -808,6 +815,7 @@
false, // TURN_ON_SCREEN
false, // GET_ACCOUNTS
false, // RUN_IN_BACKGROUND
+ false, // AUDIO_ACCESSIBILITY_VOLUME
};
/**
@@ -878,6 +886,7 @@
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 @@
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 6a73829..ef2db4a 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 @@
}
}
+ /**
+ * 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 3b3e070..b199984 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -698,7 +698,13 @@
@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 cf794c5..e222fee 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -349,7 +349,9 @@
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 @@
}
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 @@
}
}
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 f1d0e10..827e026 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -18,6 +18,7 @@
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.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 @@
@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 @@
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 @@
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 @@
: 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 @@
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 @@
: 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 @@
: 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 @@
: 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 @@
: 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 @@
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 @@
: 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 @@
: 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 @@
: 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 @@
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 @@
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 @@
}
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().unbroadcastIntent(
+ ActivityManager.getService().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1212,7 +1213,7 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
try {
- return ActivityManagerNative.getDefault().checkPermission(
+ return ActivityManager.getService().checkPermission(
permission, pid, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1556,7 +1571,7 @@
}
try {
- return ActivityManagerNative.getDefault().checkPermissionWithToken(
+ return ActivityManager.getService().checkPermissionWithToken(
permission, pid, uid, callerToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1641,7 +1656,7 @@
@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 @@
@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 @@
@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 @@
@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 @@
return mOuterContext;
}
- final IBinder getActivityToken() {
+ @Override
+ public IBinder getActivityToken() {
return mActivityToken;
}
@@ -2197,10 +2213,11 @@
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 27a0200..3464c4d 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -30,10 +30,11 @@
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 @@
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 @@
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 @@
(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 @@
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 @@
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 @@
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 ba79108..45652ef 100644
--- a/core/java/android/app/EphemeralResolverService.java
+++ b/core/java/android/app/EphemeralResolverService.java
@@ -40,6 +40,7 @@
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 @@
* @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 @@
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 @@
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 @@
}
} 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 b5b6e4a..6a79e6c 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -34,9 +34,10 @@
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 @@
});
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 8124232..10ab2bc 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -414,6 +414,10 @@
// 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 @@
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 @@
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
}
+ mPerformedCreateView = true;
return onCreateView(inflater, container, savedInstanceState);
}
@@ -2690,6 +2695,7 @@
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 5a2c5e7..9ea3f83 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -387,7 +387,7 @@
* 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 @@
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 @@
}
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);
-
- 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);
+ 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;
}
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 @@
}
f.mContainer = null;
f.mView = null;
+ f.mInLayout = false;
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
@@ -1340,6 +1335,19 @@
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 @@
}
}
- 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 @@
// 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 @@
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 @@
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 @@
}
// 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 d27dff5..088fd08 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -24,7 +24,8 @@
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 @@
&& 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 @@
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);
+ OneShotPreDrawListener.add(sceneRoot, () -> {
+ if (enterTransition != null) {
+ enterTransition.removeTarget(nonExistentView);
+ ArrayList<View> views = configureEnteringExitingViews(
+ enterTransition, inFragment, sharedElementsIn, nonExistentView);
+ enteringViews.addAll(views);
+ }
- 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);
- }
-
- 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 @@
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 @@
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);
+ OneShotPreDrawListener.add(sceneRoot, () -> {
+ ArrayMap<String, View> inSharedElements = captureInSharedElements(
+ nameOverrides, finalSharedElementTransition, fragments);
- if (inSharedElements != null) {
- sharedElementsIn.addAll(inSharedElements.values());
- sharedElementsIn.add(nonExistentView);
- }
+ 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);
+ 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;
- }
- });
+ 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 92d67b7..82be7ab 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -75,73 +75,78 @@
* {@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 @@
* @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 @@
* @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 @@
*/
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 @@
* 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 @@
*
* @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 @@
* 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 @@
* @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 c2b5b93..6b962b9 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -51,35 +51,31 @@
* {@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 @@
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 ee869ea..260b80c 100644
--- a/core/java/android/app/IEphemeralResolver.aidl
+++ b/core/java/android/app/IEphemeralResolver.aidl
@@ -21,5 +21,8 @@
/** @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 6c8c4d6..405a3d8 100644
--- a/core/java/android/app/IInstrumentationWatcher.aidl
+++ b/core/java/android/app/IInstrumentationWatcher.aidl
@@ -21,7 +21,7 @@
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 ee81c58..15b99c6 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -94,8 +94,8 @@
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 cae54b6..848464c 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -53,6 +53,16 @@
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 fa8d0c9..64cb9b1 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -26,7 +26,7 @@
/**
* 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 @@
* 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 f934a9f..cc7981c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1505,7 +1505,7 @@
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 @@
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 @@
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 @@
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 @@
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 da99e80..725cc29 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -21,6 +21,7 @@
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 @@
private IWindowManager mWM;
private ITrustManager mTrustManager;
private IUserManager mUserManager;
+ private Context mContext;
/**
* Intent used to prompt user for device credentials.
@@ -87,8 +89,12 @@
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 @@
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 @@
}
- 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 7754244..94d24e4 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -339,39 +339,43 @@
* 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;
+ // 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;
- 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);
+ 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 (outLibPaths != null) {
- outLibPaths.add(instrumentationLibDir);
- if (!instrumentationLibDir.equals(instrumentedLibDir)) {
- outLibPaths.add(instrumentedLibDir);
+ if (!instrumentationAppDir.equals(instrumentedAppDir)) {
+ outZipPaths.add(instrumentedAppDir);
+ if (instrumentedSplitAppDirs != null) {
+ Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+ }
}
- }
- if (!instrumentedAppDir.equals(instrumentationAppDir)) {
- instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+ if (outLibPaths != null) {
+ outLibPaths.add(instrumentationLibDir);
+ if (!instrumentationLibDir.equals(instrumentedLibDir)) {
+ outLibPaths.add(instrumentedLibDir);
+ }
+ }
+
+ if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+ instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+ }
}
}
@@ -452,7 +456,7 @@
if (mRegisterPackage) {
try {
- ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
+ ActivityManager.getService().addPackageDependency(mPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -891,7 +895,7 @@
StrictMode.onIntentReceiverLeaked(leak);
}
try {
- ActivityManagerNative.getDefault().unregisterReceiver(
+ ActivityManager.getService().unregisterReceiver(
rd.getIIntentReceiver());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -917,7 +921,7 @@
StrictMode.onServiceConnectionLeaked(leak);
}
try {
- ActivityManagerNative.getDefault().unbindService(
+ ActivityManager.getService().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1046,7 +1050,7 @@
// 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 @@
+ " 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 @@
}
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 bdb2685..1fd082f4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2239,7 +2239,7 @@
/**
* Returns the id of the channel this notification posts to.
*/
- public String getNotificationChannel() {
+ public String getChannel() {
return mChannelId;
}
@@ -2803,10 +2803,6 @@
* 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 @@
*
* 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 @@
* 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 f259c6d..bfabc0d 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -48,8 +48,9 @@
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 @@
* @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 @@
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 @@
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 @@
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 @@
// 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 @@
/**
* Returns the notification sound for this channel.
*/
- public Uri getRingtone() {
- return mRingtone;
+ public Uri getSound() {
+ return mSound;
}
/**
@@ -304,7 +305,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
", 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 cfa242b..02d5705 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -339,7 +339,7 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 void cancel() {
try {
- ActivityManagerNative.getDefault().cancelIntentSender(mTarget);
+ ActivityManager.getService().cancelIntentSender(mTarget);
} catch (RemoteException e) {
}
}
@@ -833,7 +833,7 @@
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 @@
@Deprecated
public String getTargetPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -882,7 +882,7 @@
@Nullable
public String getCreatorPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -910,7 +910,7 @@
*/
public int getCreatorUid() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getUidForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -941,7 +941,7 @@
@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 boolean isTargetedToPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.isIntentSenderTargetedToPackage(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -970,7 +970,7 @@
*/
public boolean isActivity() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.isIntentSenderAnActivity(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -984,7 +984,7 @@
*/
public Intent getIntent() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getIntentForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -998,7 +998,7 @@
*/
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 2d15beb..45831a3 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -826,7 +826,8 @@
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 @@
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 ee6a3ac..c529e4b 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -946,7 +946,7 @@
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 f38c0d8..3ecc309 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -322,10 +322,10 @@
}});
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 b859418..54cc4a0 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -768,7 +768,7 @@
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 0046b0e..2e21729 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -241,6 +241,35 @@
}
/**
+ * 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 360087c..d89d2bb 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -285,6 +285,27 @@
= "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 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 @@
}
/**
- * 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 @@
} 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 538e52b..0196312 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,19 +20,21 @@
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.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 @@
* @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 @@
}
/**
- * 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 @@
* {@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 b0aec8c..d14e0d0 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 @@
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 6b720c0..a6f2366 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -515,6 +515,7 @@
String mIdPackage;
String mIdType;
String mIdEntry;
+ int mAutoFillId = View.NO_ID;
int mX;
int mY;
int mScrollX;
@@ -539,6 +540,7 @@
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 @@
}
}
}
+ 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 @@
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 @@
}
}
}
+ 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 @@
}
/**
+ * 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 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 da5aa61..6cd4e92 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -182,10 +182,10 @@
/**
* 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 @@
* 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 353c640..3de159a 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,6 +25,7 @@
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 @@
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 74302f2..9dfc4b4 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -20,6 +20,7 @@
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 @@
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 bb344a6..b0e27a4 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -604,10 +604,6 @@
*/
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 @@
}
/**
- * 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 a395aa4..0261b1b 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -22,6 +22,7 @@
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 @@
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 f46a3b3..28421eb 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,6 +20,7 @@
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 @@
@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 93790fe..c7c64c4 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -20,6 +20,7 @@
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 @@
@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 4949c24..8d77888 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -20,6 +20,7 @@
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 @@
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 252e3d2..e3288f3 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -22,6 +22,7 @@
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 @@
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 7f57acf..2e73051 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -371,7 +371,7 @@
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 744f942..2a026a9 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -22,6 +22,7 @@
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 @@
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 eab4c6f..9f00e1a 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -23,6 +23,7 @@
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 @@
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 e70c936..89c1bf8 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -24,6 +24,7 @@
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 @@
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 96a1ae8..7c5458b 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -100,7 +100,6 @@
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 6ad442b..dde0ac6 100755
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -54,7 +54,7 @@
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 96c59e2..541583f 100755
--- a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
+++ b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
@@ -24,7 +24,7 @@
*
* {@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 feccdce..0da4e88 100644
--- a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
@@ -21,7 +21,7 @@
*
* {@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 f53ca94..9e87230 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -30,10 +30,24 @@
* @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 OobData() { }
private OobData(Parcel in) {
+ leBluetoothDeviceAddress = in.createByteArray();
securityManagerTk = in.createByteArray();
leSecureConnectionsConfirmation = in.createByteArray();
leSecureConnectionsRandom = in.createByteArray();
@@ -77,6 +92,7 @@
@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 26f2dea..5d27662 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -111,12 +111,6 @@
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 @@
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 @@
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 @@
} 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 @@
// 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 @@
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 @@
}
}
// Registration failed.
- mAdvertiserId = -1;
+ mAdvertiserId = -2;
notifyAll();
}
}
@@ -348,7 +342,7 @@
// 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 10e6fb2..231dace 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 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 @@
} 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 @@
* 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 1e6424e..f369409 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -42,6 +42,7 @@
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 @@
}
}
+ @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 @@
}
/**
+ * 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 9221fbb..fd6cddb 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -147,13 +147,7 @@
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 @@
}
}
+ /** @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 4769bd0..eadc013 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -355,6 +355,20 @@
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 @@
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 @@
}
}
+ 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 daa1b93..54dcd0a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -23,7 +23,7 @@
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 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 @@
}
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 @@
}
/**
+ * 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 @@
@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 @@
@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 @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 @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 322cc7b..5fa4275 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -32,6 +32,10 @@
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 @@
* 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 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 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 edc8d82..7533655 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 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 4afe38b..ee8a22f 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -65,6 +65,9 @@
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 @@
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 4eecd48..50589fe 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1713,6 +1713,16 @@
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 @@
* 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 @@
* 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 @@
* {@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 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 @@
= "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 32ca6c2..4adb5b7 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 @@
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 @@
@Deprecated
public String getTargetPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -226,7 +226,7 @@
*/
public String getCreatorPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -245,7 +245,7 @@
*/
public int getCreatorUid() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getUidForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -266,7 +266,7 @@
*/
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 74ec8e4..9b99bbf 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -489,6 +489,13 @@
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 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 @@
*
* @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 @@
*
* @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 @@
*
* @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 @@
* 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 @@
/** {@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 0000000..0674e7c
--- /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 0000000..7f2b3ee1
--- /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 fc3b958..f620088 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 @@
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, 0xFFFFFFFF, -1);
- mFilters.addAll(filters);
+ 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);
+ }
+
+ 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 @@
return mPackageName;
}
+ @Deprecated
public List<IntentFilter> getFilters() {
+ return mLegacyFilters;
+ }
+
+ public List<EphemeralIntentFilter> getIntentFilters() {
return mFilters;
}
@@ -90,6 +123,7 @@
out.writeParcelable(mDigest, flags);
out.writeString(mPackageName);
out.writeList(mFilters);
+ out.writeList(mLegacyFilters);
}
public static final Parcelable.Creator<EphemeralResolveInfo> CREATOR
@@ -103,21 +137,6 @@
}
};
- /** @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 @@
*
* @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 @@
| (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 0000000..6e569f7
--- /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 11f0eb6..d753a6e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -492,7 +492,7 @@
/**
* 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 052fa61..b3dd0e5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3514,6 +3514,36 @@
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 1f013ae..ad0a6b2 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 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 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 b5df4d7..f8b4570 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -65,7 +65,7 @@
* 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 a93870e..f7c4d59 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -193,7 +193,11 @@
* 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 @@
*
* <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 8233ad2..c46fe29 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -553,6 +553,7 @@
if (!mPreloading && useCache) {
final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
if (cachedDrawable != null) {
+ cachedDrawable.setChangingConfigurations(value.changingConfigurations);
return cachedDrawable;
}
}
@@ -588,9 +589,11 @@
// 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 f17fd55..cdf7013 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -19,7 +19,7 @@
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 @@
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 d2c3d755..3fe645c 100644
--- a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
+++ b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
@@ -25,7 +25,7 @@
*
* @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 c99cb0c..a7dd035 100644
--- a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -24,7 +24,7 @@
*
* @hide
*/
-interface IFusedLocationHardwareSink {
+oneway interface IFusedLocationHardwareSink {
/**
* Event generated when a batch of location information is available.
*
@@ -50,4 +50,4 @@
* 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 45aeb4a..025d46d 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -88,10 +88,10 @@
/* 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 0000000..cf4d8a2
--- /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 1ac9fca..e7436be 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -108,6 +108,26 @@
*/
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 a5b4eb5..e0a026e 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -38,9 +38,15 @@
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 @@
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 252385f..263750a 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 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 7b7533b..0136979 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -75,36 +75,35 @@
/**
* 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 @@
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 @@
* re-enabled.
*/
public static void setDumpDisabled(String msg) {
- synchronized (Binder.class) {
- sDumpDisabled = msg;
- }
+ sDumpDisabled = msg;
}
/**
@@ -400,10 +450,7 @@
}
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 @@
}
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 @@
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 e5832c8..0d6d369 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -924,16 +924,4 @@
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 58acbcf..c7bf0fd 100644
--- a/core/java/android/os/CountDownTimer.java
+++ b/core/java/android/os/CountDownTimer.java
@@ -125,19 +125,28 @@
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();
+ long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
+ long delay;
- // special case: user's onTick took more than interval to
- // complete, skip to next interval
- while (delay < 0) delay += mCountdownInterval;
+ 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 0e7da63..481b2dc 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 @@
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 3546e17..819afb4 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -77,6 +77,7 @@
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 @@
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 640105c..e11494d 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -36,7 +36,8 @@
}
// Find the service manager
- sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
+ sServiceManager = ServiceManagerNative
+ .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
@@ -52,7 +53,7 @@
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 @@
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 e9a3936..ef79b66 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -17,7 +17,6 @@
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 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 @@
// 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 d31036c..6a751e8 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -77,6 +77,7 @@
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 @@
}
}
}
+
+ /*
+ * 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 15dd282..50eb7cf 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -26,7 +26,6 @@
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 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 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 @@
@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 @@
@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 @@
/** {@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 61ba4d5..a86ba59 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
similarity index 89%
rename from core/java/android/os/storage/IMountServiceListener.aidl
rename to core/java/android/os/storage/IStorageEventListener.aidl
index 0e20cd3..4ba1dbe 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.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
similarity index 90%
rename from core/java/android/os/storage/IMountService.aidl
rename to core/java/android/os/storage/IStorageManager.aidl
index 390df99..98cbce6 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -19,8 +19,8 @@
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 @@
* @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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 @@
/**
* 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 @@
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
similarity index 91%
rename from core/java/android/os/storage/IMountShutdownObserver.aidl
rename to core/java/android/os/storage/IStorageShutdownObserver.aidl
index f3e1654..b284217 100644
--- a/core/java/android/os/storage/IMountShutdownObserver.aidl
+++ b/core/java/android/os/storage/IStorageShutdownObserver.aidl
@@ -24,9 +24,9 @@
*
* @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 1942fde..0472e02 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -152,7 +152,7 @@
/** @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 @@
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 @@
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 @@
final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
mLooper);
try {
- mMountService.registerListener(delegate);
+ mStorageManager.registerListener(delegate);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -410,7 +410,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/** {@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 @@
/** {@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 @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 @@
/** {@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 @@
/** {@hide} */
public void mount(String volId) {
try {
- mMountService.mount(volId);
+ mStorageManager.mount(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -730,7 +730,7 @@
/** {@hide} */
public void unmount(String volId) {
try {
- mMountService.unmount(volId);
+ mStorageManager.unmount(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -739,7 +739,7 @@
/** {@hide} */
public void format(String volId) {
try {
- mMountService.format(volId);
+ mStorageManager.format(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -748,7 +748,7 @@
/** {@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 @@
/** {@hide} */
public void partitionPublic(String diskId) {
try {
- mMountService.partitionPublic(diskId);
+ mStorageManager.partitionPublic(diskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -766,7 +766,7 @@
/** {@hide} */
public void partitionPrivate(String diskId) {
try {
- mMountService.partitionPrivate(diskId);
+ mStorageManager.partitionPrivate(diskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -775,7 +775,7 @@
/** {@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 @@
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 @@
/** {@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 @@
/** {@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 @@
/** {@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 @@
/** {@hide} */
public void forgetVolume(String fsUuid) {
try {
- mMountService.forgetVolume(fsUuid);
+ mStorageManager.forgetVolume(fsUuid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -851,7 +851,7 @@
*/
public String getPrimaryStorageUuid() {
try {
- return mMountService.getPrimaryStorageUuid();
+ return mStorageManager.getPrimaryStorageUuid();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -865,7 +865,7 @@
*/
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 @@
/** {@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 @@
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 @@
/** {@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 @@
/** {@hide} */
public void destroyUserKey(int userId) {
try {
- mMountService.destroyUserKey(userId);
+ mStorageManager.destroyUserKey(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1103,7 +1103,7 @@
/** {@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 @@
/** {@hide} */
public void lockUserKey(int userId) {
try {
- mMountService.lockUserKey(userId);
+ mStorageManager.lockUserKey(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1121,7 +1121,7 @@
/** {@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 @@
/** {@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 @@
/** {@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 @@
}
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 @@
/** {@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 @@
/** {@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 @@
/** @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
similarity index 98%
rename from core/java/android/os/storage/MountServiceInternal.java
rename to core/java/android/os/storage/StorageManagerInternal.java
index 17aaef9..d102b19 100644
--- a/core/java/android/os/storage/MountServiceInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -21,7 +21,7 @@
*
* @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 8e7db31..c843887 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -18,7 +18,7 @@
/**
* 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 7b0d2a4..46f2d38 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -332,7 +332,7 @@
* {@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 2dcf220..383cae1 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -106,6 +106,22 @@
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 @@
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 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 b826584..a280e59 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -41,6 +41,8 @@
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 de19f81..c4684e7 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -18,11 +18,13 @@
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.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 @@
}
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 1b905a0..0946906 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -369,6 +369,22 @@
"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 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 @@
"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 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 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 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 0000000..5f27e34
--- /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 0000000..fe21615
--- /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 0000000..2308440
--- /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 0000000..62950b4
--- /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 0000000..d6d4f39
--- /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 0000000..76a2561
--- /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 0000000..bb122e5
--- /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 455e1b2..813acc2 100644
--- a/core/java/android/service/carrier/CarrierService.java
+++ b/core/java/android/service/carrier/CarrierService.java
@@ -107,12 +107,12 @@
* <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 4a956c6..4b272e9 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -22,11 +22,8 @@
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 8c35901..f639c0d 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -28,7 +28,7 @@
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 @@
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 0000000..4e00c64
--- /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 e606ebf..45011eb 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -77,6 +77,7 @@
* </p>
*/
public abstract class NotificationListenerService extends Service {
+
// TAG = "NotificationListenerService[MySubclass]"
private final String TAG = NotificationListenerService.class.getSimpleName()
+ "[" + getClass().getSimpleName() + "]";
@@ -146,6 +147,48 @@
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 @@
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 @@
@Override
public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
- NotificationRankingUpdate update) {
+ NotificationRankingUpdate update, int reason) {
StatusBarNotification sbn;
try {
sbn = sbnHolder.get();
@@ -941,6 +1010,7 @@
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 @@
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 @@
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 928d5d8..0000000
--- 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 be0b47c..dfb6b86 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 @@
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 @@
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 @@
this.postTime = postTime;
this.key = key();
this.groupKey = groupKey();
+ this.channel = null;
}
public StatusBarNotification(Parcel in) {
@@ -113,6 +112,7 @@
}
this.key = key();
this.groupKey = groupKey();
+ this.channel = NotificationChannel.CREATOR.createFromParcel(in);
}
private String key() {
@@ -182,6 +182,7 @@
} else {
out.writeInt(0);
}
+ this.channel.writeToParcel(out, flags);
}
public int describeContents() {
@@ -208,14 +209,14 @@
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 @@
}
/**
+ * 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 e9bbc2d..12aed25 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -119,6 +119,8 @@
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 b3f2c2a..c0948a6 100644
--- a/core/java/android/text/Editable.java
+++ b/core/java/android/text/Editable.java
@@ -121,8 +121,10 @@
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 f9afcc7..fd6fc7d 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -634,6 +634,17 @@
}
/**
+ * 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 ae5d356..39b78eb 100644
--- a/core/java/android/text/Spannable.java
+++ b/core/java/android/text/Spannable.java
@@ -46,15 +46,17 @@
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 bdbe8b0..081be3a 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -836,7 +836,7 @@
here = endPos;
breakIndex++;
- if (mLineCount >= mMaximumVisibleLineCount) {
+ if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
return;
}
}
@@ -920,7 +920,25 @@
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 @@
}
}
-
if (needMultiply && !lastLine) {
double ex = (below - above) * (spacingmult - 1) + spacingadd;
if (ex >= 0) {
@@ -960,6 +977,15 @@
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 @@
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 @@
}
}
}
-
+ mEllipsized = true;
mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart;
mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
}
@@ -1243,6 +1252,25 @@
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 @@
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 03a2d62..c411860 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -850,6 +850,11 @@
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 479f493..6e4d78d 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -242,14 +242,20 @@
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 0000000..2e4319c
--- /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 f4eb132..1abc10d 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 @@
* 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;
- /**
- * Smallest negative value a half-precision float may have.
- */
- public static final short LOWEST_VALUE = (short) 0xfbff;
+ public static final @HalfFloat short EPSILON = (short) 0x1400;
+
/**
* Maximum exponent a finite half-precision float may have.
*/
- public static final short MAX_EXPONENT = 15;
- /**
- * Maximum positive finite value a half-precision float may have.
- */
- public static final short MAX_VALUE = (short) 0x7bff;
+ public static final int MAX_EXPONENT = 15;
/**
* Minimum exponent a normalized half-precision float may have.
*/
- public static final short MIN_EXPONENT = -14;
+ public static final int MIN_EXPONENT = -14;
+
+ /**
+ * Smallest negative value a half-precision float may have.
+ */
+ public static final @HalfFloat short LOWEST_VALUE = (short) 0xfbff;
+ /**
+ * Maximum positive finite value a half-precision float may have.
+ */
+ 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 @@
* @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 @@
* @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 @@
* @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 @@
}
}
- 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 @@
* @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 @@
// 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 @@
* @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 @@
* <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 @@
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 a81eef8..d59be02 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -32,6 +32,11 @@
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 7a3c95e..8eca431 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -26,6 +26,8 @@
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 @@
*/
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 @@
*/
private RenderNode(long nativePtr) {
mNativeRenderNode = nativePtr;
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
mOwningView = null;
}
@@ -154,19 +164,7 @@
* 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 @@
// 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 0bb84cc..5012215 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -18,7 +18,7 @@
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 @@
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 441f330..02a8521 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6703,6 +6703,11 @@
} 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 5a6cf7d..1ff8fb0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -26,7 +26,7 @@
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 @@
}
}
+ /**
+ * Notify that the window title changed
+ */
+ public void onWindowTitleChanged() {
+ mAttachInfo.mForceReportNewAttributes = true;
+ }
+
public void handleDispatchWindowShown() {
mAttachInfo.mTreeObserver.dispatchOnWindowShown();
}
@@ -7077,7 +7084,7 @@
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 2e4ba74..e9ff9d0 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -275,4 +275,7 @@
/** @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 ec852e8..85d10f1 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -142,11 +142,17 @@
* @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 @@
* @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 @@
* @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 @@
}
}
+ /** @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 @@
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);
+ final View view = inflateViewNoAdd(parent);
+ replaceSelfWithView(view, parent);
- 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);
-
+ mInflatedViewRef = new WeakReference<>(view);
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
}
@@ -317,4 +345,18 @@
*/
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 8a9bb33..82379c4 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -509,6 +509,11 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 8038089..2f12e9b 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -34,6 +34,54 @@
*/
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 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 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 b39705e..7104a28 100644
--- a/core/java/android/view/inputmethod/InputContentInfo.java
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -18,11 +18,14 @@
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 @@
*/
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 @@
@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 @@
* @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 @@
@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 @@
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 f4ea90b..eb0c44c 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 @@
@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 @@
// 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 bc6e7b4..c206974 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 @@
try {
sZygote = new ZygoteProcess("webview_zygote", null);
- String packagePath = sPackage.applicationInfo.sourceDir;
- String libsPath = sPackage.applicationInfo.nativeLibraryDir;
+ // 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 " + packagePath + " " + libsPath);
- sZygote.preloadPackageForAbi(packagePath, libsPath, Build.SUPPORTED_ABIS[0]);
+ 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 9d228cf..bbc50da 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -312,10 +312,10 @@
}
/**
- * 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 5eaabe7..541fbe0 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -111,6 +111,8 @@
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 @@
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 @@
// 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 b2a77d0..a9268d4e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -58,6 +58,7 @@
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 @@
// 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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
* and can be searched.
*/
private static class ViewTree {
- private final View mRoot;
+ private View mRoot;
private ArrayList<ViewTree> mChildren;
@@ -3643,7 +3642,7 @@
}
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 @@
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 @@
}
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 @@
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 9c48cf8..69f463c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -148,6 +148,8 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
///////////////////////////////////////////////////////////////////////////
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
/**
* 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 @@
}
/**
- * 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 @@
}
}
+ /**
+ * 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 @@
* 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 @@
* 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 @@
.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 @@
.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 @@
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 @@
desired = Math.max(desired, dr.mDrawableHeightRight);
}
- desired += pad;
+ desired += getCompoundPaddingTop() + getCompoundPaddingBottom();
- 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 += 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 @@
}
}
+ /**
+ * 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 @@
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 0000000..0a14d3e
--- /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 3b6073a..d8f7907 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -70,7 +70,7 @@
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 83ad9dc..459071b 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -19,7 +19,7 @@
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 @@
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 @@
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 015e60d..0b27c60 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -19,7 +19,7 @@
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 @@
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 472f583..9936ed5 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -18,7 +18,7 @@
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 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 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 1e26c92..dd8ef18 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.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.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 @@
setProfileSwitchMessageId(intent.getContentUserHint());
try {
- mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
+ mLaunchedFromUid = ActivityManager.getService().getLaunchedFromUid(
getActivityToken());
} catch (RemoteException e) {
mLaunchedFromUid = -1;
@@ -864,7 +863,7 @@
} 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 4e3c3fc..a3134b3b 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.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 @@
/**
* 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 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 @@
// 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 @@
// 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 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 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 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 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 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 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 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 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 ef725da..a94f308 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.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 0000000..b392186
--- /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 80c55fb..7591488 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -27,6 +27,8 @@
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 e57a224..304c31d 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 @@
}
// 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 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 e76b395..f904150 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 @@
/**
* 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 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 @@
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 @@
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 @@
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 @@
}
}
+ @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 11dd0e8..d968e3c 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 @@
@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 594b6ab..c03bcdf 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 @@
}
// 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 e1118d8..cdd267e 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.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 @@
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 @@
}
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 @@
}
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 bed7c1ba..eb75bd4 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.Intent;
import android.net.Uri;
import android.os.Build;
+import android.os.UserHandle;
import android.provider.Settings;
/**
@@ -72,7 +73,7 @@
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 878f3a6..2a004cfb 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.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 @@
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 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 0543442..944cd32 100644
--- a/core/java/com/android/internal/policy/PipMotionHelper.java
+++ b/core/java/com/android/internal/policy/PipMotionHelper.java
@@ -18,7 +18,7 @@
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 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 cbacf26..62d506f 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -41,8 +41,12 @@
// 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 @@
}
/**
+ * 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 @@
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 4748e6f..7ee5170 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -268,6 +268,45 @@
}
/**
+ * 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 0000000..83866c2
--- /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 0000000..98ffd82
--- /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 71252fb..b0bc81b 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.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 @@
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 @@
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 @@
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 @@
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 429131b..168da5f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -25,6 +25,7 @@
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 @@
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 @@
return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
}
+ public ArraySet<String> getPrivAppPermissions(String packageName) {
+ return mPrivAppPermissions.get(packageName);
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -507,6 +515,8 @@
associatedPkgs.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
+ } else if ("privapp-permissions".equals(name) && allowAppConfigs) {
+ readPrivAppPermissions(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
@@ -584,4 +594,32 @@
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 91e8310..a4e9576 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -211,6 +211,7 @@
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 @@
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 e10fdbd..3456839 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -915,6 +915,16 @@
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 @@
{"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 657b1ef..7e417b4 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -93,17 +93,15 @@
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 7fc79d2..c920b8d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -70,7 +70,7 @@
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 899c2da..8934c1e 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -72,9 +72,6 @@
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 fbccfd5..4391d93 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 @@
}
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 1a33d91..10090a1 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 @@
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_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];
- const IServiceManager::Version kVersion {
- .major = static_cast<uint16_t>(versionMajor),
- .minor = static_cast<uint16_t>(versionMinor),
- };
+ 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);
+ }
+
+ 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 jobject JHwBinder_native_getService(
JNIEnv *env,
jclass /* clazzObj */,
- jstring serviceNameObj,
- jint versionMajor,
- jint versionMinor) {
+ jstring ifaceNameObj,
+ jstring serviceNameObj) {
+
+ if (ifaceNameObj == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
if (serviceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
- if (versionMajor < 0
- || versionMajor > 65535
- || versionMinor < 0
- || versionMinor > 65535) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return NULL;
+ const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
+ if (ifaceName == NULL) {
+ return NULL; // XXX exception already pending?
}
-
- const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
-
+ 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 @@
"(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 6bd82e9..0920488 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 7387b29..a10d807 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if (err == OK) { \
size_t childHandle; \
\
- err = vec->writeEmbeddedToParcel( \
+ err = ::android::hardware::writeEmbeddedToParcel( \
+ *vec, \
parcel, \
parentHandle, \
0 /* parentOffset */, \
@@ -507,7 +510,8 @@
if (err == OK) {
size_t childHandle;
- err = vec->writeEmbeddedToParcel(
+ err = ::android::hardware::writeEmbeddedToParcel(
+ *vec,
parcel,
parentHandle,
0 /* parentOffset */,
@@ -567,7 +571,8 @@
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 @@
\
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 @@
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 @@
}
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 @@
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 5dace6b..8844fb0 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -220,6 +220,11 @@
}
}
+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 @@
(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 a58bc90..d70fbb9 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -178,7 +178,11 @@
// 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 1743731..b9376d8 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -111,7 +111,7 @@
}
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 f88de51..dd2a7a9 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -124,10 +124,6 @@
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 @@
// 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 af117d1..da059e3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -319,12 +319,6 @@
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 @@
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 @@
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 @@
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 @@
}
} 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 b78b8ff..e270911 100644
--- a/core/jni/fd_utils-inl.h
+++ b/core/jni/fd_utils-inl.h
@@ -241,6 +241,18 @@
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 @@
}
}
- 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 (android::base::StartsWith(path, kOverlayDir)
- && android::base::EndsWith(path, kApkSuffix)
+ if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
+ || StartsWith(path, kVendorOverlayDir))
+ && EndsWith(path, kApkSuffix)
&& 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)) {
+ 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;
+ }
+
+ // 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 4eebea6..fbad143 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
similarity index 73%
rename from core/res/res/drawable/watch_switch_track_material.xml
rename to core/res/res/color/watch_switch_track_color_material.xml
index 79e92a3..c7dc5d3 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
similarity index 100%
rename from core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png
rename to core/res/res/drawable-hdpi/watch_switch_track_mtrl.png
Binary files differ
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
similarity index 100%
rename from core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png
rename to core/res/res/drawable-xhdpi/watch_switch_track_mtrl.png
Binary files differ
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
similarity index 100%
rename from core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png
rename to core/res/res/drawable-xxhdpi/watch_switch_track_mtrl.png
Binary files differ
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 0ab56f9..08eecef 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 aefe28f..dac1e32 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 2fe13de..960b927 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 ae8f203..22e66d5 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 5881cf0..a1a845a 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 36e8e57..731fe16 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 995272a..77b6930 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 5ca9f43..e43f1ba 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 18fc6dd..af8c592 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 3451bcc..b3c24e5 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 1f0d164..7e9c508 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 2509eae..6caf561 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 f5f1e62..c076db2 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 f6eb810..2d6bdb2 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 f873b1c..21b737a 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 7cb46fe..80ee407 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 07f6aa8..35b2918 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 0e6ba82..95a6728 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 628f9bb..a628e42 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 05155ca..86f2070 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 4283827..4ce3a1f 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 38f2b88..72c1271 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 38f2b88..72c1271 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 38f2b88..72c1271 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 1277acc..738af8c 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 77b43b1..3c2915d 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 d7ee50c..96b060f 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 e7f3f02..6ccd864 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 374183f..e8e61f4 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 9b6d57c..dbfd8ba 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 034b291..501627d 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 1e5f6a1..ccff4f3 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 704667a..89a9471 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 cd3e7be..cbb0d9e4a4 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 c8b3256..e833052 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 3fc3346..e811b94 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 825672b..b0ce160 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 af7aaaf..2ba22af 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 05fe8d0..09223cd 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 cd41f51..105a647 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 ec7f8f9..564472e 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 290a31f..d4b9bf1 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 02736ec..e2432f1 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 1e34347..5e069b6 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 9a227c4..729f726 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 2491f82..c3e939e 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 732a321..7f80a29 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 f0cfd0b..444c83d 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 7a48ae5..2b592bd 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 26c9053..3a96743 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 c7806f2..d60a010 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 6ea7d6b..7afb2ce 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 1d7a45b..c66ed12 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 a0a361b..a210f5b 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 3f228203..139e02a 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 beb6a67..fc3eb40 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 bd80f84..2faf1634 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 758b21b..99465cc 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 60330e5..1e7e281 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 c18ff7f..99d6423 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 0371543..324f0d7 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 e039927..caf3688 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 13218b7..0848304 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/config_material.xml b/core/res/res/values-notround-watch/config_material.xml
deleted file mode 100644
index a99674f..0000000
--- a/core/res/res/values-notround-watch/config_material.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
--->
-
-<!-- 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>
diff --git a/core/res/res/values-notround-watch/dimens_material.xml b/core/res/res/values-notround-watch/dimens_material.xml
index 9cacb11..9fdf55b 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 d3476aa..3e886bc 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 a7571ef..92a2e2a 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 24265ee..bf9e15d 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 6270210..e09daa5 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 24265ee..bf9e15d 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 29c0a59..7f96d2e 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 1179870..ae4a6ee 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 f2de4e0..c8f27b1 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 ed6c798..9e25bb7 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 91d5bbe..b106464 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 5c129af..50af3cc 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 76f1e66..5bc756b 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 0fb3ebe..1095088 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 fdf8a6d..27d7cad 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 340010f..b048762 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 4832546..6cfd253 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 f6bb25c..b391912 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 24bfebd..5ec586f 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 818bb9f..15cbd94 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 81c5fd0..31666ee 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 9983142..0126068 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 fb0fda8..104badd 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 d6eae64a..f8224f2 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 5b7cf74..78b5400 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 42e0b0a..ca5e3bc 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 18bfd4d..72f589b 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 529f18b..03d3637 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/drawable/watch_switch_track_material.xml b/core/res/res/values-watch/dimens.xml
similarity index 65%
copy from core/res/res/drawable/watch_switch_track_material.xml
copy to core/res/res/values-watch/dimens.xml
index 79e92a3..4c8b39c 100644
--- a/core/res/res/drawable/watch_switch_track_material.xml
+++ b/core/res/res/values-watch/dimens.xml
@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
+
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
+
http://www.apache.org/licenses/LICENSE-2.0
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android: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>
+<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 af4207e..0053c12 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -98,7 +98,7 @@
<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 aa1594d..fbe780d 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 @@
<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 68e87c2..2126d12 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 62bb44a..bdd9fe3 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 0500c07..3c2146b 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 849f292..011e4f7 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 c3967e4..2d61e6e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8335,4 +8335,15 @@
<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 89691e9..8f0350a 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 92426c6..37feff8 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 ff1d383..d4119d0 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 840a551..8737df8 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 30e7b31..ebe577c 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 c06a93d..ed68582 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 cce02f2..d42ec90 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 92fff65..c719664 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 ff8693b..0de773b 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -175,6 +175,7 @@
<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 @@
<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 9e45d09..d7b38e8 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 @@
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 8d91192..0cf3a84 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 19d0a73..6809508 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
similarity index 68%
rename from tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml
rename to core/tests/coretests/res/layout/remote_views_text.xml
index 5322411..a265d2e 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 0000000..d532749
--- /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 f28ba7e..e9e8bfc 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 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 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 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 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 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 06c495e..5af2667 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 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 @@
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 @@
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 b5f0617..a15cba0 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.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 @@
}
}
- 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 @@
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 @@
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 @@
}
}
- /* 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 fcc6389..4f2387d 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -18,14 +18,14 @@
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 @@
@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 0000000..cd26804
--- /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 4f724fe..e9a810d 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
}
String mPath = Environment.getExternalStorageDirectory().toString();
- int ret = getMs().mountVolume(mPath);
+ int ret = getSm().mountVolume(mPath);
return ret == StorageResultCode.OperationSucceeded;
}
@@ -567,7 +567,7 @@
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 @@
// 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 @@
}
}
- class ShutdownObserver extends IMountShutdownObserver.Stub{
+ class ShutdownObserver extends IStorageShutdownObserver.Stub{
private boolean doneFlag = false;
int statusCode;
@@ -683,10 +683,10 @@
}
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 @@
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 e6d3158..0a32e43 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -349,6 +349,7 @@
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 7ba46be..b6b0e68 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.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.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 @@
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 134ac0c..6718259 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -18,30 +18,17 @@
########################
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)
+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)
-#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 $(BUILD_PREBUILT)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
new file mode 100644
index 0000000..3fc7914
--- /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 619fd26..b51e6d9 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -390,7 +390,9 @@
<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 79c63ee..e628cf8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1241,6 +1241,11 @@
* #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 @@
* @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 98d45dc..554e5d2 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1442,6 +1442,28 @@
}
/**
+ * 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 @@
@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 40a2833..00b5eda 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.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.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 @@
* <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 @@
* <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 @@
* 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 e83104d..3a12419 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -77,36 +77,27 @@
* <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 @@
* <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 @@
* <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 6763dd1..318bfb6 100644
--- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
+++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
@@ -218,4 +218,13 @@
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 4fc7892..e566b9d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -26,6 +26,7 @@
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 @@
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 @@
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 ae789d6..e068900 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -74,6 +74,7 @@
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 7d1e328..907d914 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3204,7 +3204,7 @@
{
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 0441b9d..becd307 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -66,6 +66,11 @@
* 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 8dc502a..fdf4d52 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -24,6 +24,7 @@
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 @@
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 @@
LayerUpdateQueue.cpp \
Matrix.cpp \
OpDumper.cpp \
+ OpenGLReadback.cpp \
Patch.cpp \
PatchCache.cpp \
PathCache.cpp \
@@ -95,7 +98,6 @@
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
similarity index 76%
rename from libs/hwui/Readback.cpp
rename to libs/hwui/OpenGLReadback.cpp
index 1645218..408159b 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 @@
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 0000000..f4ebabc
--- /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 e410d71..9c4cb09 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -133,7 +133,7 @@
// Shaders
bool hasBitmap;
- bool isBitmapNpot;
+ bool useShaderBasedWrap;
bool hasVertexAlpha;
bool useShadowAlphaInterp;
@@ -180,7 +180,7 @@
modulate = false;
hasBitmap = false;
- isBitmapNpot = false;
+ useShaderBasedWrap = false;
hasGradient = false;
gradientType = kGradientLinear;
@@ -234,7 +234,7 @@
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 1afc978..0c2309f 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -707,7 +707,7 @@
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 @@
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 55c943c..b763953 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 @@
/**
* 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 7c97e77..5e21dfc 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -738,7 +738,7 @@
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 971c2a3..34e6a06 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -58,7 +58,7 @@
}
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 @@
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 b8f7d9f..d6b6548 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -227,7 +227,7 @@
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 @@
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::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 3940381..663238c 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -85,6 +85,10 @@
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 a52abfc..f172473 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -65,23 +65,6 @@
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 1ea99fd..3ee916c 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -37,8 +37,6 @@
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 a06cc37..8dd165c 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -45,6 +45,7 @@
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 10a1db9..c9b5f00 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -48,6 +48,14 @@
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 @@
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 84122d7..6742743 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::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 @@
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 50bc6c3..ca43156 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 @@
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 ed0a7ebd..1be630c 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -48,6 +48,9 @@
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 dca78b3..37126a6 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -18,6 +18,7 @@
libutils \
libEGL \
libGLESv2 \
+ libvulkan \
libskia \
libui \
libgui \
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 13a0ed8..f2af4a8 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -23,36 +23,41 @@
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 91e2744..4319895 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -33,6 +33,7 @@
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 accbabd..7dcbbd0 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -164,6 +164,14 @@
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 a204d5c..6973209 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -215,7 +215,7 @@
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 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 4abaa90..2ad7f74 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -53,11 +53,15 @@
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 0988d7e..904d57e0 100644
--- a/libs/hwui/pipeline/skia/SkiaLayer.h
+++ b/libs/hwui/pipeline/skia/SkiaLayer.h
@@ -30,6 +30,7 @@
{
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 ca7ee8b..7f3474a 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 @@
profileCanvas->flush();
}
+ // Log memory statistics
+ if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
+ dumpResourceCacheUsage();
+ }
+
return true;
}
@@ -116,10 +121,16 @@
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 0000000..a18d264
--- /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 0000000..d914409
--- /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 69e603b..c5a40d4 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -48,9 +48,11 @@
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 @@
return;
}
+ layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
layerCanvas->clear(SK_ColorTRANSPARENT);
RenderNodeDrawable root(layerNode, layerCanvas, false);
@@ -266,6 +269,20 @@
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 877a353..c1c8cbe 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -100,7 +100,10 @@
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 21f3488..ca394b2 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 @@
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 @@
currentFrameInfo->markSwapBuffers();
if (*requireSwap) {
- mWindowContext->swapBuffers();
+ mVkManager.swapBuffers(mVkSurface);
}
- mBackbuffer.reset();
-
return *requireSwap;
}
@@ -108,6 +119,7 @@
}
DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
+ mVkManager.initialize();
Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
return new DeferredLayerUpdater(layer);
}
@@ -116,33 +128,24 @@
}
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 cdc8692..aab1d7a 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 @@
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 @@
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 c322efb..0174b86 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -84,7 +84,7 @@
* 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 afeeef8..177a729 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::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 39e5931..022e871 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 @@
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 @@
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 e559142..44a5a14 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 @@
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 9688340..e13d0ce 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 @@
, 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 @@
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 @@
"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 d8677e13..d121bcf 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -37,6 +37,7 @@
namespace uirenderer {
+class Readback;
class RenderState;
class TestUtils;
@@ -46,6 +47,7 @@
class DispatchFrameCallbacks;
class EglManager;
class RenderProxy;
+class VulkanManager;
class TaskQueue {
public:
@@ -92,12 +94,15 @@
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 @@
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 0000000..4d239bc
--- /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 0000000..f0e3320
--- /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 0000000..9b0b950
--- /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 0000000..bc6fc64
--- /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 ebc1dd7..1f56222 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 @@
// 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 da724a9..bbaf267 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -182,7 +182,7 @@
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 d68f5bd..398e7a8 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -113,7 +113,7 @@
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 @@
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 9771c85..b5abf5b 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 @@
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 d05bdbf..cea84c0 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 @@
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 @@
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 fe1ee02..fa3d8bd 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -553,7 +553,7 @@
}
};
-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 6a093fd..033d70d 100644
--- a/libs/storage/IMountServiceListener.cpp
+++ b/libs/storage/IMountServiceListener.cpp
@@ -34,7 +34,7 @@
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 6114d4a..e5de603 100644
--- a/libs/storage/IMountShutdownObserver.cpp
+++ b/libs/storage/IMountShutdownObserver.cpp
@@ -31,7 +31,7 @@
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 8870d2a..e86ad1a 100644
--- a/location/java/android/location/IFusedProvider.aidl
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -22,11 +22,11 @@
* 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 5a5fdc6..d4ff0dd 100644
--- a/location/java/android/location/IGeofenceProvider.aidl
+++ b/location/java/android/location/IGeofenceProvider.aidl
@@ -23,6 +23,6 @@
*
* {@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 89709ee..5440f0f 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -584,6 +584,10 @@
* @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 @@
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 @@
}
}
- /** @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 @@
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 @@
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 @@
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 f24bf09..435e6ba 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -335,6 +335,9 @@
/** @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 384be5c..28c7253 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -63,13 +63,15 @@
/** 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 @@
"STREAM_BLUETOOTH_SCO",
"STREAM_SYSTEM_ENFORCED",
"STREAM_DTMF",
- "STREAM_TTS"
+ "STREAM_TTS",
+ "STREAM_ACCESSIBILITY"
};
/*
@@ -773,7 +776,8 @@
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 b5e3af0..43fb4b9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1513,9 +1513,9 @@
}
@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 @@
}
@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 d77a082..bbb7184 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2189,9 +2189,9 @@
/**
* 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 4b1e39f..5f6686a 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -26,14 +26,14 @@
*/
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 2348ab7..52a68bf 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 @@
/* 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 82cf965..36ad90b 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1826,8 +1826,8 @@
}
@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 @@
}
@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 b262d97..690a553 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -39,6 +39,11 @@
*/
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 @@
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 @@
void baseStart() {
synchronized (mAppOpsLock) {
if (isRestricted_sync()) {
- playerSetVolume(0, 0);
+ playerSetVolume(true/*muting*/,0, 0);
}
}
}
@@ -114,7 +118,7 @@
return;
}
}
- playerSetVolume(leftVolume, rightVolume);
+ playerSetVolume(false/*muting*/,leftVolume, rightVolume);
}
int baseSetAuxEffectSendLevel(float level) {
@@ -124,7 +128,7 @@
return AudioSystem.SUCCESS;
}
}
- return playerSetAuxEffectSendLevel(level);
+ return playerSetAuxEffectSendLevel(false/*muting*/, level);
}
/**
@@ -159,11 +163,18 @@
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 @@
}
}
-
/**
* 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 @@
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 9fafda4..b429e22 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -35,9 +35,6 @@
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 @@
* 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 @@
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 @@
}
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 @@
* 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 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 @@
* @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 @@
}
}
- 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 @@
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 9b217fb..8d4271f 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -31,6 +31,7 @@
libutils \
libbinder \
libmedia \
+ libmediadrm \
libskia \
libui \
liblog \
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index d2dc440..87092d0 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -60,6 +60,7 @@
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::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 @@
{
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
- if (mAudioTrack != NULL)
+ if (mAudioTrack != NULL && !mMuted)
mAudioTrack->setVolume(leftVolume, rightVolume);
}
@@ -1042,6 +1056,19 @@
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 aff101f..5c48a90 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -114,13 +114,14 @@
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 @@
unsigned long mToggle;
bool mAutoPaused;
int mPrevSampleID;
+ bool mMuted;
};
// application object for managing a pool of sounds
@@ -168,6 +170,7 @@
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 @@
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 ab3e340..9d0c1f8 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -132,6 +132,15 @@
}
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 @@
"(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 aa756ed..3060df2 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -82,7 +82,7 @@
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 440cb64..2b69d5b 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 bfc9ff3..7fa5736 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.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 @@
Handler mHandler;
IBackupManager mBackupManager;
- IMountService mMountService;
+ IStorageManager mStorageManager;
FullObserver mObserver;
int mToken;
boolean mIsEncrypted;
@@ -158,7 +158,7 @@
}
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 @@
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 c2ca998..f442219 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 b77ff10..531e517 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 2feb51f..0000000
--- 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 9af20d0..8cf375a 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.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.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 @@
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 @@
}
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 0474df7..e3ab05d 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.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 @@
// 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 66e56e0..6a2949a 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_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 @@
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 @@
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 3fcc600..6b2c1ee 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -485,6 +485,24 @@
}
}
+ @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 194e8c7..ef2e0a5 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 @@
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 43cc1d6..d95af61 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 @@
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 @@
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 a50391f..2450be3 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 1bebebc..7b0a291 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.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 23c6615..4b51917 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.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 74582f3..6f0caa2 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.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 295248c..34d236b 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 bb50087..d0abbf9 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 829123c..0eebcd7 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 483770f..c0b776e 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 5498580a..cbb2271 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 f233db9..12f103d 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 cd77792..23adb5a 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 a011fcf..09988ed 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 1df5ec9..561af92 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 92e9005..19382ec 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 8ec531c..5276b3a 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 a65c58f..0c56b8d 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 923eca1..60f373b 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 3c0247d..032d73d 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 8ed7444..57738e8 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 8ed7444..57738e8 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 8ed7444..57738e8 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 cdfbc01..e0b5bb7 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 2a21d22..259e7fb 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 644bf59..7d70efe 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 2217611..952fda8 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 88ed7fa..e998b69 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 d26fc05..bf96b59 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 58aab1d..e2eb10d 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 91bbaf0..282ae4a 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 b717382..f4bb7ad 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 5605189..1cded3d 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 d579ec4..a2a6e04 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 94229b1..76f04bd 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 34f06e5..f5f6916 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 9428e17..6dcb745 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 a382e37..07241b5 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 44517a8..8e8307b 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 7a32827..d894ccf 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 2e85770..2ee38ef 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 00e323c..8b2d784 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 2b9e8cb..609cb33 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 0037c11..92d7783 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 235ea6a..46cc6ce 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 d7c8d03..cf8f382 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 21bbc3f..03c0edf 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 ca716cae..a2eb86d 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 0108c2c..41a8eef 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 154864f..6930c7a 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 df91cb1..7734881 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 42bc33f..711b949 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 a6017d5..8bcbf79 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 cb6327a..4fa3779 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 b6adb4f..20f64fe 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 9886d3e..cf77254 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 935ad40..9db8348 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 18b6f60..cc4e5678 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 478e19d..a8a918b 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 5dcad7a..8bb4579 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 b678aac..f19ba3e 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 77a23f2..4db3e6e 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 588ca67..7855beb 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 763cb70..2c366c6 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 588ca67..7855beb 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 6a2122a..5d0b965 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 1f192c1..d301ce1 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 e415544..f21793b 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 7e636fe7..b478ecf 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 78fa3fd..b9da0eb 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 ad4cf61..c17376b 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 02eb615..2cf68a5 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 a936c3e..975a4aa 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 25f79b6..f14cbdd 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 9e9e92c..2640122 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 27f8e09..60a4d72 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 6005972..fbb67bc 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 e9feded..50c43bb 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 0e73b7b..c5ae71c 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 1015e1c..b538545 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 61dc5ab..0b5e8a0 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 a6f9ab8..8d1056a 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 f09e0e5..21e5b75 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 7268dcd..ba657c6 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 ac9de74..60f56f1 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 f17b523..6bb7308 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 1fc551f..6714b27 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 972fc73..f176aac 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 381f903..c3acf0b 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.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 9608daa..24ede16 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 @@
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 857ca49..4bfca9b 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 @@
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 org.xmlpull.v1.XmlPullParserException;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -65,28 +68,41 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 b27aad9..7e3f67b 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 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 ed411be..f3658c3 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 @@
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 @@
mCategoryByKeyMap.put(category.key, category);
}
backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+ normalizePriority(context, mCategoryByKeyMap);
+ filterDuplicateTiles(mCategoryByKeyMap);
}
}
@@ -163,4 +170,81 @@
}
}
}
+
+ /**
+ * 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 57e06dd..703e9d2 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.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 @@
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 f93c566..b209f4e 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 @@
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 380f622..573ec1f0 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 @@
// 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 dd543a3..d784a3a 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 @@
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 bf48e5d..1c51773 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 @@
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 169b01f..461573f 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 @@
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 2170cc1..935d09b 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -5,6 +5,13 @@
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 227d0e9..d4c7c7a 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 b33da19..9bef2db 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 772c344..47abd4f 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.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 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.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 @@
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 @@
*/
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 @@
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 @@
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 @@
@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 @@
stopSelfWhenDone();
return;
}
- poll();
break;
case INTENT_BUGREPORT_FINISHED:
if (id == 0) {
@@ -367,15 +363,6 @@
return;
}
-
- private void poll() {
- if (pollProgress()) {
- // Keep polling...
- sendEmptyMessageDelayed(MSG_POLL, POLLING_FREQUENCY);
- } else {
- Log.i(TAG, "Stopped polling");
- }
- }
}
/**
@@ -397,11 +384,12 @@
}
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 @@
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 @@
.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 @@
}
/**
- * 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 @@
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 @@
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 @@
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 @@
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 @@
* <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 @@
this.id = id;
this.pid = pid;
this.name = name;
- this.max = max;
+ this.max = this.realMax = max;
}
/**
@@ -1750,14 +1655,17 @@
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 @@
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 f6e558f..15ce90f 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -40,8 +40,7 @@
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 b4bfb01..4e3744a 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_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 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 @@
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 @@
}
}
+ /*
+ * 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 @@
// 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 2adb261..0b5383a 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 0000000..af55e8b
--- /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 0000000..a9d1fa9
--- /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 c64b188..62d3ce4 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 @@
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 @@
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 85f2e2a..60cf312 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.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.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import dalvik.system.PathClassLoader;
@@ -163,6 +166,16 @@
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 @@
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 @@
}
}
-
// 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 0000000..688df46
--- /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
similarity index 93%
rename from packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 4947863..a9874fc 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.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 0000000..cff770a
--- /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 7af247e..9ab8ac63 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 0339e03..f09657f 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 1131b2a..5294c9c 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 0dc05e6..601930a 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 755438e..a1a8f8d 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 87b4433..1bc9e59 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 e173890..8105d9e 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 207e223..83c67d4 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 16c94d7..bf3a614 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 feaa453..bd599bc 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 f361b93..5ba720c 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 8bedecd..927e75b 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 0ff0f93..69629a9 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 b112405..8e34bd0 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 9721362..b3a457d 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 276b856..050d7f8 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 ca2e5b3..9aca3cc 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 ca2e5b3..9aca3cc 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 ca2e5b3..9aca3cc 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 81696f6..90c2ca1 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 aa9578a..0a45ac1 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 ab81af5..84fadb2 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 3617074..d6578a2 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 48f0b954..e00c5b5 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 5e1ca4b..08572fe 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 765e0aa..830bfa7 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 e66d342..3b138c2 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 5ccf4a0..579335d 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 84f9105..48a6d0f 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 89b5a6f..97f3926 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 3c5812f..7ff63bda 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 f83ba28..bd0805b 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 4ce22e4..07966cf 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 4efffc56..6444ae5 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 4875888..7e08a01 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 98a24248..8ffb10d 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 ce73705..a6d7983 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 c45fa4f..6ef9f73 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 a151b8f..695279d 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 6c0c967..ba71182 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 d3e97cc..b222555 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 cbd71f9..b2a6f27 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 3827dba..cefb57a 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 56c8360..e013c6b 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 47a49da..94e789a 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 c4676fa..5af5979 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 a8266dd..503c8c8 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 c5e2500e..62fc350 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 a1a3b31..9e7d2f2 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 9b83058..04fb4c2 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 8003890..a21019a 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 1a16967..ce94295 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 17b6802..8ab1de0 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 cb691c5..c6312e1 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 97f5f5e..f87223c 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 43c577d..29f8875 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 6ef8674..f25662b 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 03e599c..78c6102 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 d6e02d6..dbb0373 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 0ae421d..0dbdcb9 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 6ad19f9..d037cda 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 0ae421d..0dbdcb9 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 70ef6ea..e33ebb5 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 41ec367..0fbb0bd 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 8f65531..c4d2378 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 276c266..23daf91 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 cda2ac9..90985e7 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 33b2d5b..9616c07 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 11d05b7..667c65d 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 46e3f05..0a95017 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 43aa36d..afc5ee4 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 364173e..99b8439 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 c1e55c8..c1aeb09b 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 f2b1772..0c461b4 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 f58ed17..caa9f97 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 e7b1abb..030c97f 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 886a138..c086fff 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 31d90e2..ff46ad3 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 78ad148..f2d2661 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 ba49055..48b1e4f 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 7a7991f..94c3af1 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 4f7ffe5..5785af9 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 2de07e3..6562b39 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 6be736a..e3c419b 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 9eea375..0f5d37e 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 37a7e38..331d09e 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 ce636cd..18cb930 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 f09d6e9..74d5d6c 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 e1d6a94..c4698c3 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.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 @@
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 4f3ffde..ef1c25d 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -17,7 +17,6 @@
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 @@
@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 @@
@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 9a64a41..3a8536b 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 @@
UserInfo currentUser;
try {
- currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUser = ActivityManager.getService().getCurrentUser();
} catch (RemoteException e) {
return;
}
@@ -96,7 +96,7 @@
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 @@
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 99e7876..b207984 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.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.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 @@
* 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 @@
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 b1f454e..965ded5 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.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 b39803a..f8b73a1 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 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 4cfc811..5b10756 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 @@
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 @@
}
/** 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 @@
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 fb940b5..e081b53 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 @@
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 b3038b9..870d4d1 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 @@
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 c633aa1..951b27f 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 @@
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 bb4ea2d..9cc927d 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 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 94cbdd4..78b96b3 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 @@
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 9df8113..84b22ea 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 @@
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 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 @@
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 @@
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 @@
private void requestPulse(final int reason, boolean performedProxCheck) {
Assert.isMainThread();
- if (mPulsePending || !canPulse()) {
+ if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
return;
}
@@ -306,20 +309,11 @@
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 0000000..6d0e77c
--- /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 0000000..85cde10
--- /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 0000000..e107fcd
--- /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 816d70d..fe9f55f 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 @@
@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 9ae341a..34dc63f 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 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 @@
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 @@
return;
}
- if (!mKeyguardDonePending) {
- KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
- }
+ tryKeyguardDone(true);
if (strongAuth) {
mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
}
@@ -545,7 +543,8 @@
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 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 @@
// 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 void handleDismiss(boolean allowWhileOccluded) {
if (mShowing && (allowWhileOccluded || !mOccluded)) {
- mStatusBarKeyguardViewManager.dismiss();
+ mStatusBarKeyguardViewManager.dismissAndCollapse();
}
}
@@ -1493,6 +1492,16 @@
}
};
+ 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 @@
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 @@
// 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 @@
}
};
+ private final Runnable mHideAnimationFinishedRunnable = () -> {
+ mHideAnimationRunning = false;
+ tryKeyguardDone(true);
+ };
+
/**
* Handle message sent by {@link #hideLocked()}
* @see #HIDE
@@ -1697,16 +1711,10 @@
return;
}
mHiding = true;
- if (mShowing && !mOccluded) {
- if (!mHideAnimationRun) {
- mStatusBarKeyguardViewManager.startPreHideAnimation(mKeyguardGoingAwayRunnable);
- } else {
- mKeyguardGoingAwayRunnable.run();
- }
- } else {
- // Don't try to rely on WindowManager - if Keyguard wasn't showing, window
- // manager won't start the exit animation.
+ if (mShowing && !mOccluded) {
+ mKeyguardGoingAwayRunnable.run();
+ } else {
handleStartKeyguardExitAnimation(
SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
mHideAnimation.getDuration());
@@ -1806,7 +1814,7 @@
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
setShowingLocked(true);
- mStatusBarKeyguardViewManager.verifyUnlock();
+ mStatusBarKeyguardViewManager.dismissAndCollapse();
}
Trace.endSection();
}
@@ -1969,7 +1977,11 @@
}
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 7b8d27e..43cfa32 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 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 0000000..e8e8a4d
--- /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 a359380..c6dde46 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 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.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.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 @@
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 @@
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 @@
}
};
- 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 @@
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 @@
// Reset back to default
mEnableSwipeToDismiss = true;
mEnableDragToDismiss = true;
+ mEnableMinimizing = false;
+ setMinimizedState(false);
mEnableTapThrough = false;
mIsTappingThrough = false;
mEnableSnapToEdge = false;
@@ -211,6 +232,9 @@
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 @@
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 @@
}
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();
+ for (PipTouchGesture gesture : mGestures) {
+ if (gesture.onUp(mTouchState)) {
+ break;
}
- } 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();
- }
- }
- } 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 @@
}
/**
+ * 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 @@
}
/**
+ * @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 @@
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 @@
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 @@
}
/**
+ * 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 @@
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 0000000..17d9864
--- /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 5b93aa2..a622656 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 @@
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 e1cd143..dc42adc 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.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 @@
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 @@
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 @@
@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 @@
if (mHost != null) {
mHost.removeCallback(this);
}
- TunerService.get(mQsContainer.getContext()).removeTunable(this);
+ TunerService.get(mQs.getContext()).removeTunable(this);
}
@Override
@@ -124,7 +127,7 @@
} 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 @@
}
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 @@
// 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 f345172..f4da5ec 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 @@
@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 @@
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 @@
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 @@
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 @@
protected int calculateContainerHeight() {
int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
- : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
- + mHeader.getCollapsedHeight();
+ : (int) (mQsExpansion * (heightOverride - mHeader.getHeight()))
+ + mHeader.getHeight();
}
- 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;
- }
-
- 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 2b9320b..5027144 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 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 0000000..c8f1670
--- /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 c699e27..e55ff70 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.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 @@
protected boolean mExpanded;
protected boolean mListening;
- private QSContainer.Callback mCallback;
+ private QS.Callback mCallback;
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
@@ -171,7 +171,7 @@
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 39ce324..4341d17 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.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 cf2c16d..9bbead4 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.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 @@
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 @@
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 @@
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 8d7f6ee..f2c3e61 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.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 dc68112..28530d7 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.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 91a0eb0..342df5e 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 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 6bc94b2..015a4c0 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 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 a980a7f..e57cd58 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.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 d89fbfd3c..fc1c1ac 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.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.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 @@
@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 18bde27..f83b279 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.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 @@
@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 61bad77..8afa91e 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.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 7de883e..1406c9f 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.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 @@
@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 5ae7a76..77f063d 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.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 aabafe1..65432dc 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.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 @@
@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 ec4ab51..198375d 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.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 0aa723e..5b1638f 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.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 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 016c4b7..dcee659 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.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 2a2cc46..f968816 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.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 5b5ecae..8a9a696 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.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 @@
@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 c02e5ae..10fde30 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 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 499eb50..cec5f15 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.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 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 cd09231c..91d38bd 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.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 b5fbfe0..246c23e 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.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 @@
@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 27306fc..3876c88 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.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 @@
@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 459e8ec..ce7fbd3 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.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 27fcf2a..7655e6c 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.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.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 @@
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 @@
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 ec99d20..af1823c 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.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 b961055..cf75c4f 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 @@
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 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 0000000..e1e654d5
--- /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 0000000..41acaa0
--- /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 0000000..057aa54
--- /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 11a4f64..2272a72 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.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.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 @@
/**
* 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 @@
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 745f5a5..178cb9f 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 @@
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 febeacb..3c7012a 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.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 936354e..8c94c35 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.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 @@
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 d44aa84..71f559b 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.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 99d98bc..de7def6 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.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 @@
}
/** 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 @@
@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 3ed2698..e8039c3 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.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 803fe48..901d47d 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.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 dd80750..005206f 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.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 15d26f9..19eefec 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 @@
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.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 @@
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 4e34bbc..47d2def 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.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 ef32f7e..c245126 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 @@
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 @@
mTmpRect5.set(mTempOtherInsetRect);
}
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.resizeDockedStack(mTmpRect1,
mTmpRect2.isEmpty() ? null : mTmpRect2,
mTmpRect3.isEmpty() ? null : mTmpRect3,
@@ -88,7 +88,7 @@
@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 @@
@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 @@
@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 23acb1b..19e511cf 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.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.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 @@
// 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 @@
@Override
public boolean onDismiss() {
try {
- ActivityManagerNative.getDefault().resumeAppSwitches();
+ ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
@@ -515,7 +514,7 @@
} 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 @@
protected void sendCloseSystemWindows(String reason) {
try {
- ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ ActivityManager.getService().closeSystemDialogs(reason);
} catch (RemoteException e) {
}
}
@@ -1820,7 +1819,7 @@
// 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 @@
// 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 @@
&& mKeyguardManager.isDeviceLocked(userId)) {
boolean canBypass = false;
try {
- canBypass = ActivityManagerNative.getDefault()
+ canBypass = ActivityManager.getService()
.canBypassWorkChallenge(intent);
} catch (RemoteException e) {
}
@@ -2058,7 +2057,7 @@
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 caf5447..5173176 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.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 f438762..f43fc40 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 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 b10fb31..bb327ef 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.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 74caa53..68d5cd4 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 @@
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 @@
apply();
applyIconTint();
- mNC.addSignalCallback(this);
+ mNC.addCallback(this);
}
@Override
@@ -232,7 +232,7 @@
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 4977202..fc39648 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 @@
}
@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 @@
}
@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 baff680..1c8c317 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.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 8a5a8a0..dd5832b 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 @@
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 66030b9..a3e1b3a 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 @@
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 b742479..a011162 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 @@
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 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 @@
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 dfb06d7..89defec 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.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.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 @@
(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 @@
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 d94def9..e4c778c 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 @@
}
mBatteryListening = listening;
if (mBatteryListening) {
- mBatteryController.addStateChangedCallback(this);
+ mBatteryController.addCallback(this);
} else {
- mBatteryController.removeStateChangedCallback(this);
+ mBatteryController.removeCallback(this);
}
}
@@ -214,7 +214,7 @@
}
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 df4566b..dd7f3cc 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 @@
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 951b096..1a46815 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.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 af9454c..4d4f9d2 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.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 0f800bb..228e8ea 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.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 df167e6..97df237 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.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 @@
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 cda0bfe..068631d 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.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.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 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 @@
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 @@
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 @@
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);
+ mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
+ }
- // 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);
- }
- });
+ @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 @@
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 @@
// 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 @@
// 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 @@
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
- mQsContainer.setHeightOverride(height);
+ mQs.setHeightOverride(height);
}
});
mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -377,7 +369,7 @@
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 void setQsExpansionEnabled(boolean qsExpansionEnabled) {
mQsExpansionEnabled = qsExpansionEnabled;
- mQsContainer.setHeaderClickable(qsExpansionEnabled);
+ if (mQs == null) return;
+ mQs.setHeaderClickable(qsExpansionEnabled);
}
@Override
@@ -571,7 +564,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mBlockTouches || mQsContainer.isCustomizing()) {
+ if (mBlockTouches || mQs.isCustomizing()) {
return false;
}
initDownStates(event);
@@ -731,7 +724,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mBlockTouches || mQsContainer.isCustomizing()) {
+ if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
return false;
}
initDownStates(event);
@@ -804,10 +797,10 @@
}
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 @@
private void setOverScrolling(boolean overscrolling) {
mStackScrollerOverscrolling = overscrolling;
- mQsContainer.setOverscrolling(overscrolling);
+ if (mQs == null) return;
+ mQs.setOverscrolling(overscrolling);
}
private void onQsExpansionStarted() {
@@ -1000,24 +994,28 @@
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 @@
}
private void updateQsState() {
- mQsContainer.setExpanded(mQsExpanded);
mNotificationStackScroller.setQsExpanded(mQsExpanded);
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
@@ -1176,6 +1173,8 @@
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 @@
}
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 @@
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 @@
}
// 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 @@
}
private void setListening(boolean listening) {
- mQsContainer.setListening(listening);
mKeyguardStatusBar.setListening(listening);
+ if (mQs == null) return;
+ mQs.setListening(listening);
}
@Override
@@ -1748,7 +1750,7 @@
}
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 boolean isQsDetailShowing() {
- return mQsContainer.isShowingDetail();
+ return mQs.isShowingDetail();
}
public void closeQsDetail() {
- mQsContainer.closeDetail();
+ mQs.closeDetail();
}
@Override
@@ -2110,7 +2112,7 @@
private final Runnable mUpdateHeader = new Runnable() {
@Override
public void run() {
- mQsContainer.getHeader().updateEverything();
+ mQs.getHeader().updateEverything();
}
};
@@ -2257,7 +2259,7 @@
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
- mQsAutoReinflateContainer.setTranslationX(translation);
+ mQsFrame.setTranslationX(translation);
}
protected void updateExpandedHeight(float expandedHeight) {
@@ -2355,4 +2357,38 @@
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 8b1fcd6..c85584e 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.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 @@
@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 @@
}
@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 @@
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 @@
}
@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 c33d91a..6f13ba5 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.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.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.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.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.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 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
(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 @@
}
}, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
}
- } else {
+ } else if (!mNotificationPanel.isCollapsing()) {
instantCollapseNotificationPanel();
}
updateKeyguardState(staying, false /* fromShadeLocked */);
@@ -4876,7 +4883,7 @@
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 @@
*/
private boolean handleLongPressBack() {
try {
- IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IActivityManager activityManager = ActivityManager.getService();
if (activityManager.isInLockTaskMode()) {
activityManager.stopSystemLockTaskMode();
@@ -5160,5 +5167,10 @@
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 7187ec2..9ee1e8f 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.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 @@
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 @@
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 @@
// listen for user / profile change.
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener, TAG);
+ ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
} catch (RemoteException e) {
// Ignore
}
@@ -162,7 +160,7 @@
// 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 @@
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 @@
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 da698d8..fc15477 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 @@
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 @@
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 void destroy() {
+ mHandlerThread.quitSafely();
+ mTiles.values().forEach(tile -> tile.destroy());
mAutoTiles.destroy();
TunerService.get(mContext).removeTunable(this);
+ mServices.destroy();
}
@Override
@@ -321,12 +325,11 @@
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 @@
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 a8b0122..28aed87 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.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 @@
@Override
protected void onDetachedFromWindow() {
setListening(false);
- mHost.getUserInfoController().remListener(this);
+ mHost.getUserInfoController().removeCallback(this);
mHost.getNetworkController().removeEmergencyListener(this);
super.onDetachedFromWindow();
}
@@ -290,9 +290,9 @@
private void updateListeners() {
if (mListening) {
- mNextAlarmController.addStateChangedCallback(this);
+ mNextAlarmController.addCallback(this);
} else {
- mNextAlarmController.removeStateChangedCallback(this);
+ mNextAlarmController.removeCallback(this);
}
}
@@ -368,7 +368,7 @@
}
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 f5c5e56..69decd7 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 @@
if (!afterKeyguardGone) {
mBouncer.showWithDismissAction(r, cancelAction);
} else {
- mBouncer.show(false /* resetSecuritySelection */);
mAfterKeyguardGoneAction = r;
+ mBouncer.show(false /* resetSecuritySelection */);
}
}
updateStates();
@@ -235,10 +235,6 @@
mDeviceWillWakeUp = !mDeviceInteractive;
}
- public void verifyUnlock() {
- dismiss();
- }
-
public void setNeedsInput(boolean needsInput) {
mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
}
@@ -333,6 +329,7 @@
}
});
} else {
+ executeAfterKeyguardGoneAction();
if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) {
mFingerprintUnlockController.startKeyguardFadingAway();
mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
@@ -372,7 +369,6 @@
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.hide(true /* destroyView */);
mViewMediatorCallback.keyguardGone();
- executeAfterKeyguardGoneAction();
updateStates();
}
}
@@ -423,6 +419,10 @@
/**
* 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 4a2d5dc..995f4dd 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 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 5696123..6217433 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 @@
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 559436b..19dcf03 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 @@
*/
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 6726c92..fc86ac3 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 @@
}
@Override
- public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+ public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
synchronized (mChangeCallbacks) {
mChangeCallbacks.add(cb);
}
@@ -99,7 +99,7 @@
}
@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 08675c4..4c1c378 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 4f880b4..15c4afe 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 @@
}
@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 0000000..9042ca6
--- /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 7713e57..6988af7 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 0fc71d3..e5f1e68 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.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 void addListener(Listener listener) {
+ public void addCallback(Listener listener) {
synchronized (mListeners) {
mListeners.add(listener);
if (mListeners.size() == 1) {
@@ -51,7 +53,7 @@
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 4e9fc76..0f77b03 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.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 @@
/**
* 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 @@
return mTorchAvailable;
}
- public void addListener(FlashlightListener l) {
+ public void addCallback(FlashlightListener l) {
synchronized (mListeners) {
if (mCameraId == null) {
tryInitCamera();
@@ -122,7 +124,7 @@
}
}
- 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 4622ea4..daf9d6b 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 44816f9..fafbdd1 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 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 29a8981..9a5f1b8 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 8d84be4..cc61605 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 @@
/**
* 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 5f1b871..082fe82 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.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 37e6a2a..1a9756f 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 @@
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 @@
}
@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 787acc5..28935bf 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.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 @@
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 7b1f707..44ec283 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.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 93c4691..722874b 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 c3bcd94..4f96496 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 @@
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 014afae..43ced48 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 @@
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 4a6e215..c09747b 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 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 @@
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 @@
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 @@
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 30d1c54..bb4b91e 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 @@
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.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 @@
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 @@
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 @@
@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 0e91b0b..bcdb62d 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.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 da58d9e..72a0e59 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.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 6e08139..9998283 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.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 0a3197c..0a962f1 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.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 14fccf2..8740a3c 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 f2f0382..dea2f50 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.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 0000000..a068172
--- /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 7f63418..f835e7d 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.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 @@
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 8e0f9b8..ca53bc4 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.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 8ca277e..42b06b2 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 @@
// 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 22d1309..12a00e9 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.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 @@
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 b5584f3..6e17cf4 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 fccb2a2..f3be945 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 static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.mock;
+
+import android.os.Handler;
+import android.os.Looper;
+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;
-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;
-
@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 5cb5e68..cb0f7a3 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.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 0000000..f87336c
--- /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 0000000..d64669d
--- /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 d943eb6..5dac8e5 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.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 @@
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 ba7c923..863f0e5 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 @@
@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 39b6412..5c87fb0 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 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 @@
@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 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 0000000..6ceaead
--- /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 8eecfcf..5401c30 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 @@
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.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 @@
@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 d7ff04f..782a489 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.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.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 @@
@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 @@
@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 0000000..74b6127
--- /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 6c9cfe0..136e7c0 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.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 @@
// 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 0000000..34f2e01
--- /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 0000000..f40fe4c
--- /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 0000000..63bb5e7
--- /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 0000000..5179823
--- /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 45734b6..a79ae50 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -327,9 +327,6 @@
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.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 48bc27e..45f2ec7 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -22,6 +22,27 @@
// 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 @@
// 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 3385bed..2911983 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -22,6 +22,7 @@
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 bf60e47..6404604 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 @@
// 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 @@
// 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 0000000..a1f19fd
--- /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 0000000..d70c439
--- /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 0000000..e409cb0
--- /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 0000000..6406b8a
--- /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 6375e9a..8151c8a 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 @@
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.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 @@
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 @@
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 @@
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 11586ee..88a8385 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -19,8 +19,9 @@
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 8e01e9e..581aa05d 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -18,7 +18,6 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
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 @@
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 @@
@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 @@
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 @@
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 7c2eea3f..570843e 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.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 @@
}
}
- 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 b88a45e..573ad63 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.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 @@
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 6456048..f7068cf 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.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.util.Map;
@@ -118,7 +119,6 @@
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 @@
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 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
quietMode ? 1 : 0, 0));
}
- private void recoverBluetoothServiceFromError() {
+ private void recoverBluetoothServiceFromError(boolean clearBle) {
Slog.e(TAG,"recoverBluetoothServiceFromError");
try {
mBluetoothLock.readLock().lock();
@@ -1907,6 +1900,10 @@
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 de70026..5eceb9f1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5342,6 +5342,7 @@
// 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 466633a..07322fc 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 @@
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 74ff41c..eb2cd0b 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -248,7 +248,7 @@
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 553cb07..830a6ed 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.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 3f4972b..57cdc94 100644
--- a/services/core/java/com/android/server/InputContentUriTokenHandler.java
+++ b/services/core/java/com/android/server/InputContentUriTokenHandler.java
@@ -18,7 +18,7 @@
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 @@
}
try {
- mPermissionOwnerToken = ActivityManagerNative.getDefault()
+ mPermissionOwnerToken = ActivityManager.getService()
.newUriPermissionOwner("InputContentUriTokenHandler");
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -78,7 +78,7 @@
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 @@
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 2698f95..3dfbdc3 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.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.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.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 @@
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 @@
+ 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 @@
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 @@
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 @@
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 a2207b2..6701431 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.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 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 @@
};
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 0000000..f72663a
--- /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 33f9234..0414b47 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -92,7 +92,7 @@
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 e0b2307..d8bd0bb 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -18,7 +18,7 @@
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 @@
// 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 @@
// 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 e64aa16..5654096 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.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 @@
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 83d6344..f5cda0a 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -42,8 +42,10 @@
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 @@
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 356ccb3..fa5a52c 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -63,7 +63,7 @@
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 @@
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
similarity index 97%
rename from services/core/java/com/android/server/MountService.java
rename to services/core/java/com/android/server/StorageManagerService.java
index 8b7b6a0..11fabb4 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -31,7 +31,6 @@
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.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 @@
* 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 @@
@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 @@
*/
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 @@
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 @@
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 @@
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 @@
| 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 @@
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 @@
}
/**
- * 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 @@
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 @@
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 @@
*/
@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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 4f02a23..cbd7be7 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -30,7 +30,7 @@
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 @@
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 2825cf9..6ea6fb7 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -19,7 +19,6 @@
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.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 @@
}
@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 @@
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 @@
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 7802576..8fd1d2f 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.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 @@
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 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 @@
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 dc4a52d..136e02c 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 @@
// 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 @@
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 2d6832d..c8ed872 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.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.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.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.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.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 @@
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
- boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
boolean mSupportsMultiWindow;
boolean mSupportsFreeformWindowManagement;
@@ -1398,6 +1393,27 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
} 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 @@
}
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 @@
}
}
} 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 @@
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 @@
// 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 @@
@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 @@
}
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-
if (r == null) {
throw new IllegalStateException("enterPictureInPictureMode: "
+ "Can't find activity for token=" + token);
@@ -7449,21 +7509,55 @@
+ "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 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 (uidRec == null || alwaysRestrict || uidRec.idle) {
+ boolean ephemeral;
+ if (uidRec == null) {
+ ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
+ UserHandle.getUserId(uid), packageName);
+ } else {
+ ephemeral = uidRec.ephemeral;
+ }
+
+ 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 (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
packageName) != AppOpsManager.MODE_ALLOWED) {
return ActivityManager.APP_START_MODE_DELAYED;
}
}
-
- } else if (uidRec == null || uidRec.idle) {
- 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 (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 @@
// 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 @@
}
/**
+ * 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 @@
}
@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 @@
!= 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 @@
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 @@
}
@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 @@
}
}
} 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 @@
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 @@
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
- mLenientBackgroundCheck = lenientBackgroundCheck;
mSupportsLeanbackOnly = supportsLeanbackOnly;
mForceResizableActivities = forceResizable;
if (supportsMultiWindow || forceResizable) {
@@ -12993,6 +13132,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
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 @@
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 @@
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 @@
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 @@
} 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 @@
}
}
+ @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 @@
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 @@
// 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 abeea74f..14b843a 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_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 @@
private String mProfileFile;
private int mSamplingInterval;
private boolean mAutoStop;
+ private int mDisplayId;
private int mStackId;
final boolean mDumping;
@@ -169,6 +171,8 @@
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 @@
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 @@
mSamplingInterval = 0;
mAutoStop = false;
mUserId = defUser;
+ mDisplayId = INVALID_DISPLAY;
mStackId = INVALID_STACK_ID;
return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@@ -278,6 +281,8 @@
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 @@
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 @@
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 @@
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 @@
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 be8f21d..facfeb6 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.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 0d79980..473b1a3 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 @@
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 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 @@
}
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 8bb0e1a..5d8d79f 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.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.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 @@
/** 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
* 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 @@
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 @@
}
}
- /** 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 e4ec169..dff7cef 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.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.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 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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
}
}
- 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 c19a571..7a122e6 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 @@
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 c6befd7..9e29725 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 4e69162..8104a43 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.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 @@
}
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 @@
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 722974b..f618fc7 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 @@
# 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 98acc9c..9d8c383 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 @@
}
}
+ /**
+ * @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 @@
&& 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 2b00f86..1322ecf 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 @@
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 @@
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 d24c3a5..d1a15bd 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 @@
int curProcState;
int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
long lastBackgroundTime;
+ boolean ephemeral;
boolean idle;
int numProcs;
@@ -43,6 +44,7 @@
int uid;
int change;
int processState;
+ boolean ephemeral;
}
ChangeItem pendingChange;
@@ -64,6 +66,9 @@
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 9697855..a0a04bb 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.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 @@
}
}
- private IMountService getMountService() {
- return IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ private IStorageManager getStorageManager() {
+ return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
/**
@@ -980,10 +980,10 @@
// 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 48238b6..42c31b1 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 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 eb5e603..ac9545c 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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 5772a57..8d4f0a9 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 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 f1d01e0..372b2d8 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.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 @@
}
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 641c62f..42f439c 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.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 0beb227..6d96a10 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.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 @@
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 c2c1a8c..dec2f77 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 @@
/**
* @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 @@
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 6ca4e27..37221a9 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 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 0727629..886c97f 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.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 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 @@
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 @@
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 @@
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 @@
}
}
+ 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 03d95b2..11a3f11 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.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 @@
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 971989b..9c762cc 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 @@
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 @@
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 @@
}
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 @@
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 5616fb9..47701b9 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 @@
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 393199d..fbad8de 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 5297589..d65e257 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 640a46f..c70ca7f 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.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 49c4140..273bc64 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 @@
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 @@
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 @@
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 603402e..a2a55e532 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 @@
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 @@
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 5a1d896..c684a56 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 @@
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 687aaa1..461a9b0 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 @@
if (HdmiUtils.isValidAddress(newLogicalAddress)) {
return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
} else {
- return -1;
+ return Result.FAILURE_INVALID_ARGS;
}
}
@@ -320,13 +320,27 @@
* 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, int value) {
+ void setOption(int flag, boolean enabled) {
assertRunOnServiceThread();
- HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value);
- nativeSetOption(mNativePtr, flag, value);
+ 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 setLanguage(String language) {
+ assertRunOnServiceThread();
+ if (!LanguageTag.isLanguage(language)) {
+ return;
+ }
+ nativeSetLanguage(mNativePtr, language);
}
/**
@@ -336,9 +350,9 @@
* @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 @@
// <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 @@
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 @@
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 43d8bac..c85d979 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.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.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.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 @@
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 @@
* 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 @@
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 72ee218..18f1b6c 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_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.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.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.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.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 @@
*
* @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 @@
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 @@
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 @@
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 @@
} else {
HdmiLogger.error("Invalid message type:" + command);
if (callback != null) {
- callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
+ callback.onSendCompleted(SendMessageResult.FAIL);
}
}
}
@@ -884,8 +878,8 @@
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 @@
if (isTvDeviceEnabled()) {
tv().broadcastMenuLanguage(language);
- mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language));
+ mCecController.setLanguage(language);
}
}
@@ -2123,7 +2117,7 @@
}
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 @@
}
@ServiceThreadOnly
- void setCecOption(int key, int value) {
+ void setCecOption(int key, boolean value) {
assertRunOnServiceThread();
mCecController.setOption(key, value);
}
@@ -2249,7 +2243,7 @@
@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 @@
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 9aa9290..8b16411 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 @@
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 5f2d651..e1bcd99 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 @@
// 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 d80b81f6..39de8ff 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_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 @@
@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 fd7a7f9..6893012 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 @@
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 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 f69f975..4eb220f 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 @@
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 f5a0115..8b5a2931 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 @@
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 9b4950b..6633789 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 @@
@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 a209cd0..af1a85d 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 @@
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 78b40fd..01063b7 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 @@
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 2ae5c97..cab8439 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 @@
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 @@
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 16fc25f..525e223 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_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 @@
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 a37dfed..c99d8be 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 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 @@
Slog.d(TAG, "Removing jobs for package " + pkgName
+ " in user " + userId);
}
- cancelJobsForUid(pkgUid, true);
+ cancelJobsForUid(pkgUid);
}
} catch (RemoteException|IllegalArgumentException e) {
/*
@@ -455,7 +454,7 @@
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 @@
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 @@
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 @@
* 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 @@
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 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 @@
int memLevel;
try {
- memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel();
+ memLevel = ActivityManager.getService().getMemoryTrimLevel();
} catch (RemoteException e) {
memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}
@@ -1697,7 +1691,7 @@
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 5eb06ed..b44087c 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 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 @@
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 0eb8b55..8ed32f0 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 @@
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 3327b36..9740935 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 @@
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 d8103fc..c1506b9 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 @@
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 @@
}
}
- @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 @@
@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 6ebdb3c..604b3ed 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.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.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.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.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.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 @@
/** 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 @@
private int mDefaultNotificationLedOn;
private int mDefaultNotificationLedOff;
- private long[] mDefaultVibrationPattern;
private long[] mFallbackVibrationPattern;
private boolean mUseAttentionLight;
@@ -301,7 +292,7 @@
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 @@
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 @@
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 @@
}
}
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
@VisibleForTesting
- void setSystemNotificationSound(String systemNotificationSound) {
- mSystemNotificationSound = systemNotificationSound;
+ void setFallbackVibrationPattern(long[] vibrationPattern) {
+ mFallbackVibrationPattern = vibrationPattern;
}
@Override
@@ -957,15 +939,11 @@
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 @@
// 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 @@
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 @@
// bind to listener services.
mSettingsObserver.observe();
mListeners.onBootPhaseAppsCanStart();
- mRankerServices.onBootPhaseAppsCanStart();
+ mNotificationAssistants.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1682,10 +1653,10 @@
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 @@
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 @@
}
@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 @@
}
@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 @@
}
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 @@
}
}
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 @@
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 @@
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 @@
}
}
- // 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 @@
} 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 @@
&& 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);
+ 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;
}
-
- // 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;
+ 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 @@
&& (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 @@
|| (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 @@
// 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 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 @@
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 @@
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 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyRemoved(info, oldSbnLightClone, update);
+ notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
}
});
continue;
@@ -4314,7 +4172,7 @@
/**
* 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 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyRemoved(info, sbnLight, update);
+ notifyRemoved(info, sbnLight, update, reason);
}
});
}
@@ -4391,14 +4249,14 @@
}
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 a1256db..984fc38 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 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 @@
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 @@
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 @@
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;
+ stats.requestedImportance = requestedImportance;
+ stats.isNoisy = mSound != null || mVibration != null;
- 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;
- }
-
- if (isNoisy) {
- if (importance < IMPORTANCE_DEFAULT) {
- importance = IMPORTANCE_DEFAULT;
+ if (mPreChannelsNotification
+ && (getChannel().getUserLockedFields()
+ & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0) {
+ if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
+ requestedImportance = IMPORTANCE_LOW;
}
- }
- if (n.fullScreenIntent != null) {
- importance = IMPORTANCE_HIGH;
+ if (stats.isNoisy) {
+ if (requestedImportance < IMPORTANCE_DEFAULT) {
+ requestedImportance = IMPORTANCE_DEFAULT;
+ }
+ }
+
+ if (n.fullScreenIntent != null) {
+ requestedImportance = IMPORTANCE_HIGH;
+ }
+ importance = requestedImportance;
}
stats.naturalImportance = importance;
@@ -287,7 +374,10 @@
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 @@
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 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 1bb8b3b..90b3715 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 @@
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 @@
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 @@
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 @@
}
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 0000000..7ddd058
--- /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 a6a3774..2b6ce10 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.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.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 @@
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 @@
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 @@
}
}
+ /**
+ * 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 @@
}
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 ca77335..ee3f42b 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.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.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.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.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.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.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 @@
*
* <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 @@
* 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 @@
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 @@
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 @@
}
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 @@
break;
}
+ case EPHEMERAL_RESOLUTION_PHASE_TWO: {
+ EphemeralResolver.doEphemeralResolutionPhaseTwo(mContext,
+ mEphemeralResolverConnection,
+ (EphemeralRequest) msg.obj,
+ mEphemeralInstallerActivity,
+ mHandler);
+ }
}
}
}
@@ -1874,6 +1888,11 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
// 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 @@
}
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
@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 @@
}
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 @@
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 @@
}
/**
- * 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 @@
}
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 @@
@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 @@
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 @@
}
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 @@
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 @@
}
/**
- * 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 @@
}
// 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 @@
}
@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 @@
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 42cc3a8..eef8ce2 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 @@
VersionInfo ver = mVersion.get(volumeUuid);
if (ver == null) {
ver = new VersionInfo();
- ver.forceCurrent();
mVersion.put(volumeUuid, ver);
}
return ver;
@@ -2802,8 +2801,8 @@
"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 38d69ed..d558b07 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 @@
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 @@
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 37acf5c..7b877f7 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.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 @@
}
@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 @@
}
@Override
- public void onUidIdle(int uid) throws RemoteException {
+ public void onUidIdle(int uid, boolean disabled) throws RemoteException {
}
};
@@ -497,8 +496,7 @@
}
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 @@
}
}
- rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime(),
- /* forceRescan=*/ false);
+ rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime());
}
} finally {
logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
@@ -2676,8 +2673,7 @@
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 @@
// 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 @@
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 @@
// 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 @@
@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 67488ce..5b47b6f 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.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 @@
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 @@
// 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 @@
// 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 @@
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 @@
}
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 3df13a9..9fe0922 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 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 @@
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 a8bd4d2..d4adcc4 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 @@
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.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 @@
// 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 @@
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 @@
private UserInfo getCurrentUser() {
try {
- return ActivityManagerNative.getDefault().getCurrentUser();
+ return ActivityManager.getService().getCurrentUser();
} catch (RemoteException re) {
return null;
}
@@ -620,7 +619,7 @@
+ (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 b7067d2..ccdda13 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.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.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 @@
}
@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 @@
}
@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 @@
}
@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 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 @@
// 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 @@
/** {@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 @@
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 @@
/// 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 @@
}
}
}
- 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 28f36f7..f37f987 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.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 @@
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 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 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 @@
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 b457f8d..c4a0dd3 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 @@
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 f19f0aa..941cd44 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 @@
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 @@
@Override // Binder interface
public void onTrustedChanged(boolean trusted) {
mTrusted = trusted;
+ mCallback.onTrustedChanged();
}
@Override // Binder interface
@@ -114,6 +117,10 @@
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 00700b8..b215998 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.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 d755e58..1790554 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 @@
}
} 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 a920d54..cd966ef 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.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 @@
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 f3b9b18..b5aa4a9 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 @@
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 0000000..23be9a3
--- /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 62f5468..9d02940 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 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 @@
}
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 96662b5..3645c24 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.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 @@
}, 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 302f9f6..61319cf 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 @@
@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 6d97796..0a7454f 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 com.android.server.SystemService;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Arrays;
/**
@@ -259,5 +260,18 @@
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 453e745..1a77c68 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.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 @@
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 @@
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 670b9cc..49ffa22 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 @@
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 @@
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 @@
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 e1b598a..c42647e 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 @@
}
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 622eece..4569596 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.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 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 @@
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 @@
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 @@
}
}
- int rebuildWindowListUnchecked(int addIndex) {
- return super.rebuildWindowList(addIndex);
+ @Override
+ 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 false;
+ }
+ return forAllWindowsUnchecked(callback, traverseTopToBottom);
}
- @Override
- int rebuildWindowList(int addIndex) {
- if (mIsExiting && !waitingForReplacement()) {
- return addIndex;
- }
- return rebuildWindowListUnchecked(addIndex);
+ boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
+ boolean traverseTopToBottom) {
+ return super.forAllWindows(callback, traverseTopToBottom);
}
@Override
@@ -1312,6 +1317,32 @@
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 5bfece4..cf5cecda 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 @@
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 @@
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 ec4cdf2..24b9d69 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.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_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_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_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.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.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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
}
}
+ @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 @@
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 @@
* 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 @@
/** 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 @@
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);
+ forAllWindows(w -> {
+ if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w
+ + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys());
- if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + i + " = " + win
- + ", flags=" + win.mAttrs.flags + ", canReceive=" + win.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: Found new focus @ " + w);
+ mTmpWindow = w;
+ return true;
+ }, true /* traverseTopToBottom */);
+
+ if (mTmpWindow == null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
+ return null;
}
-
- 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);
-
- // 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);
- }
- }
+ 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 @@
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;
}
- }
+ }, false /* traverseTopToBottom */);
- 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;
- }
-
- 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);
+ 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();
+ });
- 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;
- }
+ // 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 @@
// 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 (willMove && w != null) {
+ 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 (updateImeTarget) {
AppWindowToken token = curTarget == null ? null : curTarget.mAppToken;
if (token != null) {
@@ -1890,24 +1249,8 @@
// 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 @@
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;
}
}
}
+
+ 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);
}
- //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);
- }
- return -1;
+ return target;
}
- 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;
-
- 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);
- }
+ mService.mInputMethodTarget = target;
+ mService.mInputMethodTargetWaitingAnim = targetWaitingAnim;
+ setInputMethodAnimLayerAdjustment(layerAdj);
+ assignWindowLayers(false /* setLayoutNeeded */);
+ }
+
+ boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) {
+ if (top.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
+ return top.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;
}
- }
- return w.isVisibleOrAdding();
- }
+ if (mTmpWindow == null) {
+ return false;
+ }
- 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 win, WindowManagerPolicy.WindowState bottom) {
- int index = -1;
- while (true) {
- if (win.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
- return win.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
+ if (w.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
+ return true;
}
// If we reached the bottom of the range of windows we are considering,
// assume no menu is needed.
- if (win == bottom) {
- return false;
+ if (w == bottom) {
+ return true;
}
- // 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);
- }
- index--;
- if (index < 0) {
- return false;
- }
- win = mWindows.get(index);
- }
+ return false;
+ });
+
+ return candidate != null && candidate.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
}
void setLayoutNeeded() {
@@ -2046,85 +1344,6 @@
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 @@
}
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 @@
*/
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 @@
}
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 @@
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 @@
}
}
- 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 @@
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 @@
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,62 +1545,43 @@
&& 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) {
- 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);
- }
-
+ final WindowState imFocus = computeImeTarget(false /* updateImeTarget */);
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;
- }
+ 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);
}
final IInputMethodClient imeClient = imFocus.mSession.mClient;
@@ -2397,83 +1598,63 @@
}
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 @@
// 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 @@
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 @@
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 @@
atoken.updateAllDrawn(this);
}
- return focusDisplayed;
+ return mTmpApplySurfaceChangesTransactionState.focusDisplayed;
}
void performLayout(boolean initial, boolean updateInputWindows) {
@@ -2699,110 +1884,110 @@
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();
+ final boolean gone = (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w))
+ || w.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
+ 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;
+ 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 ((win.mViewVisibility != GONE && win.mRelayoutCalled) || !win.mHaveFrame
- || win.mLayoutNeeded) {
+ 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);
+ 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 (win.mAttrs.type == TYPE_DREAM) {
+ } 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 @@
* @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 @@
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 @@
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 @@
}
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 @@
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 @@
}
}
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 @@
}
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 @@
}
}
+ 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 @@
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 @@
}
@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 @@
}
@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 6326148..f8b461e 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 @@
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 @@
}
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 7cb6fc3..70478fe 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 d52168c..40b737d 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 @@
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 a8eb75c..01d1c30 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 @@
// 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 @@
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 @@
}
}
- 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 @@
}
// Add all windows on the default display.
- mService.mRoot.updateInputWindows(this, mInputFocus, inDrag);
+ updateInputWindows(inDrag);
+
+ if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw");
+ }
+
+ private void updateInputWindows(boolean inDrag) {
+
+ clearInputWindowHandlesLw();
+
+ // 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);
-
- // Clear the list in preparation for the next round.
- clearInputWindowHandlesLw();
-
- if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw");
}
/* 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 377071d..2eb186b 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 @@
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 @@
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 1ccf722..01a50b7 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 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 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 @@
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 @@
// 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 @@
}
@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 @@
}
/**
+ * 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 @@
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 @@
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 @@
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 f038135..1962ca7 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 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.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_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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
WindowToken token = exitingTokens.get(i);
if (!token.hasVisible) {
exitingTokens.remove(i);
- if (token.windowType == TYPE_WALLPAPER) {
- displayContent.mWallpaperController.removeWallpaperToken(token);
- }
}
}
}
@@ -1088,17 +988,14 @@
}
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 b889db2..772833c8 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 @@
}
}
- 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 a0270c6..f2c74df 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 @@
// 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 @@
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 @@
}
// 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 void onAnimationEnd() {
synchronized (mService.mWindowMap) {
mBoundsAnimating = false;
+ mBoundsAnimationTarget.setEmpty();
mService.requestTraversal();
}
if (mStackId == PINNED_STACK_ID) {
@@ -1462,30 +1490,6 @@
}
}
- 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 2f49c82..8f4f09e 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 @@
*/
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 @@
}
void appRemoved(@NonNull AppWindowToken appWindow) {
+ if (DEBUG_UNKNOWN_APP_VISIBILITY) {
+ Slog.d(TAG, "App removed appWindow=" + appWindow);
+ }
mUnknownApps.remove(appWindow);
}
@@ -86,6 +96,9 @@
* 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 @@
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 @@
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 @@
}
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 250d381..7fd8028 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.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 @@
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 @@
// 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 @@
return mWallpaperTarget;
}
- WindowState getLowerWallpaperTarget() {
- return mLowerWallpaperTarget;
- }
-
- WindowState getUpperWallpaperTarget() {
- return mUpperWallpaperTarget;
- }
-
boolean isWallpaperTarget(WindowState win) {
return win == mWallpaperTarget;
}
@@ -135,7 +122,7 @@
*/
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 @@
+ (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 @@
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 @@
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 @@
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 @@
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 @@
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 (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
+ + " mDrawState=" + w.mWinAnimator.mDrawState);
- if (!inFreeformSpace) {
- TaskStack stack = w.getStack();
- inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ 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 @@
|| (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);
}
- }
+ return false;
+ }, true /* traverseTopToBottom */);
- 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);
-
- } 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)) {
+ || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == 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;
- }
+ 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;
+ final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null
+ && prevWallpaperTarget.mAppToken.hiddenRequested;
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "="
- + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "="
- + wallpaperTarget + " hidden=" + newTargetHidden);
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
+ + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + 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;
- }
+ 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;
+ mWallpaperTarget = prevWallpaperTarget;
}
- result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
- return true;
+ result.setWallpaperTarget(wallpaperTarget);
}
- 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");
- }
-
- result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
- return visible;
- }
-
- 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;
+ findWallpaperTarget(dc, mFindResults);
+ updateWallpaperWindowsTarget(dc, mFindResults);
- 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;
- }
+ // 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 @@
}
}
- final boolean changed = updateWallpaperWindowsPlacement(
- windows, wallpaperTarget, wallpaperTargetIndex, visible);
+ updateWallpaperTokens(visible);
- if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
- + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
- + mUpperWallpaperTarget);
-
- return changed;
+ if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
+ + " prev=" + mPrevWallpaperTarget);
}
boolean processWallpaperDrawPendingTimeout() {
@@ -725,7 +604,7 @@
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 @@
}
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 @@
}
}
- 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 0000000..8ea1b3b
--- /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 e30ebcb..f5db0b6 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 @@
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 @@
return false;
}
- /**
- * 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.
- */
- // 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);
+ // 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();
}
- return addIndex;
+ }
+
+ /**
+ * 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.
+ */
+ 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 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 @@
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 d94094a..32373f9 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 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 @@
private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>();
private WindowState mDockDivider = null;
private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
+ private int mCurBaseLayer;
+ private int mCurLayer;
+ private boolean mAnyLayerChanged;
+ private int mHighestLayerInImeTargetBaseLayer;
+ private WindowState mImeTarget;
- final void assignWindowLayers(ReadOnlyWindowList windows) {
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
+ 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 @@
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 @@
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 @@
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 f11281e..1b61fca 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 @@
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 7723752..507679b 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.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.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 @@
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 @@
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 @@
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 @@
}
if (imMayMove) {
- displayContent.moveInputMethodWindowsIfNeeded(false);
+ displayContent.computeImeTarget(true /* updateImeTarget */);
}
// Don't do layout here, the window must call
@@ -1648,8 +1632,6 @@
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 @@
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 @@
|| (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 @@
// 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 @@
+ " 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 @@
}
token.setExiting();
- if (token.windowType == TYPE_WALLPAPER) {
- dc.mWallpaperController.removeWallpaperToken(token);
- }
mInputMonitor.updateInputWindowsLw(true /*force*/);
}
@@ -3349,7 +3334,7 @@
if (mAppTransition.isTransitionSet()) {
task.setSendingToBottom(false);
}
- displayContent.rebuildAppWindowsAndLayoutIfNeeded();
+ displayContent.layoutAndAssignWindowLayersIfNeeded();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -3371,7 +3356,7 @@
if (mAppTransition.isTransitionSet()) {
task.setSendingToBottom(true);
}
- stack.getDisplayContent().rebuildAppWindowsAndLayoutIfNeeded();
+ stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -3398,7 +3383,7 @@
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 Rect getPictureInPictureMovementBounds(int displayId) {
synchronized (mWindowMap) {
if (!mSupportsPictureInPicture) {
- return new Rect();
+ return null;
}
final Rect stackBounds = new Rect();
@@ -3424,6 +3409,47 @@
}
}
+ 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 @@
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 @@
return null;
}
}
- return displayContent.screenshotApplications(appToken, displayId, width, height,
+ return displayContent.screenshotApplications(appToken, width, height,
includeFullDisplay, frameScale, config, wallpaperOnly);
}
@@ -4738,37 +4769,42 @@
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 @@
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 @@
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 @@
// 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 @@
}
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 @@
}
}
- 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 @@
mRoot.mOrientationChangeComplete = false;
w.mLastFreezeDuration = 0;
}
- }
+
+ }, true /* traverseTopToBottom */);
if (rotateSeamlessly) {
mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
@@ -4899,7 +4933,7 @@
// 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 @@
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 @@
}
synchronized (mWindowMap) {
- return mRoot.findWindow(hashCode);
+ return mRoot.getWindow((w) -> System.identityHashCode(w) == hashCode);
}
}
@@ -5405,17 +5441,16 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 972c359..d959d8c 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.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.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_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.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 @@
* 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 @@
* being visible.
*/
boolean isOnScreen() {
- if (!mHasSurface || mDestroying) {
+ if (!mHasSurface || mDestroying || !mPolicyVisibility) {
return false;
}
final AppWindowToken atoken = mAppToken;
@@ -1763,7 +1714,7 @@
final DisplayContent dc = getDisplayContent();
if (mService.mInputMethodTarget == this) {
- dc.moveInputMethodWindowsIfNeeded(false);
+ dc.computeImeTarget(true /* updateImeTarget */);
}
final int type = mAttrs.type;
@@ -1947,9 +1898,7 @@
}
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 @@
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 @@
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 @@
}
}
+ @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 @@
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 @@
}
@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;
}
- if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Re-adding window at " + index + ": " + child);
- child.mRebuilding = false;
- dc.addToWindowList(child, index);
- index++;
+ i++;
+ if (i >= count) {
+ break;
+ }
+ child = mChildren.get(i);
}
- if (!winAdded) {
- if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Re-adding window at " + index + ": " + this);
- mRebuilding = false;
- dc.addToWindowList(this, index);
- index++;
+
+ if (callback.apply(this)) {
+ return true;
}
- return index;
+
+ 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 f2682ba..de80837 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
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 b821f09..40bd3fb 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 @@
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 @@
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);
+ 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?
}
- 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;
- }
- }
- return null;
}
/** Returns true if the token windows list is empty. */
@@ -280,169 +222,6 @@
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 3a9ff5f..4d43e8e 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -19,6 +19,7 @@
$(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 @@
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_SHARED_LIBRARIES += \
libandroid_runtime \
libandroidfw \
+ libappfuse \
libbinder \
libcutils \
liblog \
@@ -64,13 +67,15 @@
libEGL \
libGLESv2 \
libnetutils \
- libhidl \
+ libhidlbase \
+ libhidltransport \
libhwbinder \
libutils \
- android.hardware.power@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.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.vr@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 a23fbcb..0c5729e 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
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);
+ // TODO(b/31632518)
+ sp<IHdmiCec> hdmiCec = IHdmiCec::getService("tv.cec");
+ if (hdmiCec == nullptr) {
+ ALOGE("Couldn't get tv.cec service.");
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);
- 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 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 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 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 nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
+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 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 @@
{ "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 e6072bb..a3ab8f6 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 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 @@
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 0000000..2f20ecd
--- /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 d69c37f..c291ba0 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -28,6 +28,7 @@
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 @@
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 0ea8d4e..c497cb1 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_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.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.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 @@
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 @@
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 @@
* 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 @@
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
+ PackageManager getPackageManager() {
+ return mContext.getPackageManager();
+ }
+
PowerManagerInternal getPowerManagerInternal() {
return LocalServices.getService(PowerManagerInternal.class);
}
@@ -1450,7 +1471,7 @@
}
IActivityManager getIActivityManager() {
- return ActivityManagerNative.getDefault();
+ return ActivityManager.getService();
}
IPackageManager getIPackageManager() {
@@ -2350,6 +2371,27 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
}
private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
+ disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
if (admin != null) {
admin.disableCamera = false;
admin.userRestrictions = null;
@@ -6039,7 +6104,6 @@
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
updateDeviceOwnerLocked();
- disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
try {
if (mInjector.getIBackupManager() != null) {
// Reactivate backup service.
@@ -6517,6 +6581,12 @@
}
}
+ 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 @@
// 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 @@
}
}
+ 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 @@
return null;
}
+ recordSecurityLogRetrievalTime();
+
ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>();
try {
SecurityLog.readPreviousEvents(output);
@@ -9180,6 +9263,8 @@
Preconditions.checkNotNull(admin);
ensureDeviceOwnerManagingSingleUser(admin);
+ recordSecurityLogRetrievalTime();
+
List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
}
@@ -9425,6 +9510,77 @@
}
}
+ @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 @@
Preconditions.checkNotNull(admin);
ensureDeviceOwnerManagingSingleUser(admin);
- if (enabled == isNetworkLoggingEnabledInternal()) {
+ if (enabled == isNetworkLoggingEnabledInternalLocked()) {
// already in the requested state
return;
}
@@ -9556,11 +9712,11 @@
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 @@
* 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 @@
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 185ccc2..8cb13da 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 @@
}
}
- 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 96884e6..29cc43f 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 @@
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 @@
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 cc96f565..1fc4378 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@
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.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.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 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 @@
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 @@
"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 @@
"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 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 @@
}
/*
- * 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 @@
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 @@
}
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 01d9304..39f14e5 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -631,6 +631,11 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
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 @@
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 6558b6e..d7666d9 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 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 @@
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 07b26e8..f4c9c86 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.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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
.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 @@
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 @@
}
}
- 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;
- }
-
- mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, mUserHandle);
-
- final long startMillis = SystemClock.uptimeMillis();
- while (true) {
- if (mRemoteInstance != null) {
- break;
+ try {
+ int flags;
+ if (mIsLowPriority) {
+ flags = Context.BIND_AUTO_CREATE;
+ } else {
+ flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
}
- final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
- final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis;
- if (remainingMillis <= 0) {
- throw new TimeoutException("Cannot get spooler!");
- }
- try {
+
+ 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!");
+ }
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 65c740f..7474a64 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 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 7c7c299..785c3fa 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 @@
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 4570a4b..39c5238 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.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 @@
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 @@
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 @@
mService.setStatusBarManager(mStatusBar);
mService.setLights(mLight);
mService.setScreenOn(false);
- mService.setSystemNotificationSound("beep!");
+ mService.setFallbackVibrationPattern(FALLBACK_VIBRATION);
}
//
@@ -161,23 +164,16 @@
false /* noisy */, true /* buzzy*/, false /* lights */);
}
+ private NotificationRecord getBuzzyBeepyNotification() {
+ return getNotificationRecord(mId, false /* insistent */, false /* once */,
+ true /* noisy */, true /* buzzy*/, false /* lights */);
+ }
+
private NotificationRecord getLightsNotification() {
return getNotificationRecord(mId, false /* insistent */, true /* once */,
false /* noisy */, true /* buzzy*/, true /* lights */);
}
- private NotificationRecord getCustomBuzzyOnceNotification() {
- 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 */);
- }
-
private NotificationRecord getCustomLightsNotification() {
return getNotificationRecord(mId, false /* insistent */, true /* once */,
false /* noisy */, true /* buzzy*/, true /* lights */,
@@ -192,6 +188,8 @@
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 @@
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 @@
} else {
builder.setVibrate(CUSTOM_VIBRATION);
}
+ channel.setVibration(true);
}
if (lights) {
if (defaultLights) {
@@ -219,6 +220,7 @@
} else {
builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
}
+ channel.setLights(true);
}
builder.setDefaults(defaults);
@@ -226,11 +228,10 @@
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 @@
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 @@
}
@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 @@
}
@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 @@
}
@Test
- public void testDemoteSoundToVibrate() throws Exception {
- NotificationRecord r = getBeepyNotification();
+ public void testNoDemoteSoundToVibrateIfVibrateGiven() throws Exception {
+ NotificationRecord r = getBuzzyBeepyNotification();
+ assertTrue(r.getSound() != null);
// 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(r.getVibration()),
+ eq(-1), (AudioAttributes) anyObject());
}
@Test
- public void testDemoteInsistenteSoundToVibrate() throws Exception {
+ public void testDemoteSoundToVibrate() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ assertTrue(r.getSound() != null);
+ assertNull(r.getVibration());
+
+ // the phone is quiet
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(FALLBACK_VIBRATION),
+ eq(-1), (AudioAttributes) anyObject());
+ }
+
+ @Test
+ 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 @@
// set up internal state
mService.buzzBeepBlinkLocked(r);
+ verifyVibrate();
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
@@ -684,14 +654,14 @@
}
@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 22b674b..6c3f447 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 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 @@
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 305b5e0..6bc9675 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 @@
.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 0000000..b8f3832
--- /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 629146f..3df0d66 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.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 @@
.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 @@
.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 @@
.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 @@
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 @@
// 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 @@
// 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 @@
// 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 ffc45ea..7a3ee7f 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 @@
.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 0000000..d6ee367
--- /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 42d9412..3114f3f 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 @@
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 bd9e6d1..ba25b16 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 @@
@Override
public void setUp() throws Exception {
super.setUp();
- service = ActivityManagerNative.getDefault();
+ service = ActivityManager.getService();
}
public void testTaskIdsForRunningUsers() throws RemoteException {
@@ -52,4 +51,4 @@
}
}
}
-}
\ 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 c9c691d..0359096 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.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 @@
@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 80be62b..4927f0c 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.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 @@
}
@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 56ff621..e55cafb 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.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.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 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 @@
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 @@
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 37430ad..d74c6dc 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.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 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 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 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 @@
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 @@
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 @@
}
@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 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 792f300..9f01773 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 @@
// 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 0000000..379d4fe
--- /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 3cfdc32..771ca146 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 @@
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 @@
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 @@
});
// 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 @@
});
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,44 +4419,29 @@
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();
+ .haveIds("ms1");
});
- // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
- // still not scanned.
+ // Update the fingerprint. CALLING_PACKAGE_1's version code hasn't changed, but we scan
+ // all apps anyway.
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";
- mInjectedCurrentTimeMillis += 1000;
- updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.checkPackageChanges(USER_0);
-
- runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertWith(getCallerShortcuts())
.haveIds("ms1", "ms2");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertWith(getCallerShortcuts())
- .isEmpty();
+ .haveIds("ms1", "ms2");
});
// Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
@@ -5721,6 +5704,7 @@
R.xml.shortcut_5);
// Unlock user-0.
+ mInjectedCurrentTimeMillis += 100;
mService.handleUnlockUser(USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5750,6 +5734,7 @@
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 @@
// hasn't changed.
shutdownServices();
+ mInjectedCurrentTimeMillis += 100;
+
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
@@ -5785,7 +5772,7 @@
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 @@
// 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 @@
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 d933cb3..207939f 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_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 @@
@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 @@
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 @@
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 0000000..0801a88
--- /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 38a98b2..ed4c79f 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 @@
}
@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 0000000..5a035d6
--- /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 3df1df9..3f47d5c 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 @@
/**
* 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 @@
@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 @@
@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 @@
}
@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 @@
@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 @@
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 0000000..9681bd2
--- /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 5326a19..d6bfa17 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.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 @@
@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 @@
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 @@
@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 @@
@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 @@
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 04104b5..7217c3b 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 @@
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 @@
@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 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 3daa87c..0544fae 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 @@
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 @@
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 a46ccee..4357dca 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 @@
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 @@
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 7dacf16..4267ec4 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 @@
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 62625bdf..c99e22a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -843,6 +843,7 @@
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 @@
}
/** {@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 @@
/** {@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 @@
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 8f9c758..2b9a508 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,6 +25,7 @@
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 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 @@
/**
* 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 @@
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 @@
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 @@
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 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 @@
* {@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 @@
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 016490c..c2a0ff1 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -515,9 +515,12 @@
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 @@
isIncoming,
isUnknown);
}
- });
+ }.prepare());
} else {
createConnection(
connectionManagerPhoneAccount,
@@ -1381,9 +1384,9 @@
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 @@
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 69de89d..5d68aae 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -87,7 +87,8 @@
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 @@
* {@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 446bbbb..ced6627 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -48,13 +48,13 @@
// 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 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 b2cf3a3..6e81053 100644
--- a/telecomm/java/android/telecom/Logging/Runnable.java
+++ b/telecomm/java/android/telecom/Logging/Runnable.java
@@ -96,4 +96,4 @@
*/
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 3a7b8c0..c45bd6b 100644
--- a/telecomm/java/android/telecom/Logging/Session.java
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -19,6 +19,7 @@
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 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 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 @@
@Override
public void writeToParcel(Parcel destination, int flags) {
destination.writeString(sessionId);
- destination.writeString(shortMethodName);
+ destination.writeString(methodPath);
}
}
@@ -226,7 +234,15 @@
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 @@
}
// 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 @@
// 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 @@
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 8ced7f81..949f7b7 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -177,8 +177,9 @@
}
// 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 @@
// 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 4a6fd7c..1900cb9 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -182,10 +182,10 @@
* @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 a4ef560..30ec5b3 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -125,13 +125,16 @@
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 473e394..0457d63 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -114,7 +114,10 @@
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 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 @@
*/
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 0e4f53e..77e0e54 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -408,6 +408,8 @@
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 @@
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 void setCamera(String cameraId) {
try {
- mVideoProviderBinder.setCamera(cameraId);
+ mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
} catch (RemoteException e) {
}
}
@@ -628,7 +631,7 @@
* @hide
*/
RemoteConnection(String callId, IConnectionService connectionService,
- ParcelableConnection connection) {
+ ParcelableConnection connection, String callingPackage) {
mConnectionId = callId;
mConnectionService = connectionService;
mConnected = true;
@@ -640,7 +643,7 @@
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 0a8470a..d8a226a 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -283,9 +283,13 @@
@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 @@
@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 e54abee..d8ede5c 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -43,6 +43,7 @@
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 @@
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 @@
/** {@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 68e5fd4..a109e90 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -30,7 +30,7 @@
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 60a27bd..1f06283 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -312,6 +312,13 @@
*/
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 @@
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 3c0a8d6..434caad 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -168,20 +168,34 @@
}
/**
- * @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 bb2b447..32f487b 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -233,7 +233,7 @@
* @hide
*/
/** @hide */
- protected int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ protected Integer mSubId;
private final Handler mHandler;
@@ -242,7 +242,7 @@
* 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 @@
* @hide
*/
public PhoneStateListener(Looper looper) {
- this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, looper);
+ this(null, looper);
}
/**
@@ -260,7 +260,7 @@
* 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 @@
* 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 e87cba1..c484fd3 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -20,6 +20,7 @@
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 @@
//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 @@
*/
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 d75dd7d..ad97a8f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -263,6 +263,22 @@
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 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 @@
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 @@
/* <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.");
+ sendUssdRequest(ussdRequest, getSubId(), callback, handler);
+ }
- 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);
+ /* <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.");
- if (resultCode == USSD_RETURN_SUCCESS) {
- callback.onReceiveUssdResponse(response.getUssdRequest(),
- response.getReturnMessage());
- } else {
- callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode);
- }
- }
+ 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 @@
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 @@
}
/**
+ * 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 5b71149..2ae424f 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 @@
*/
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 4c66be1..9c62988 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -275,10 +275,11 @@
/**
* 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 5ef71df..e443911 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -147,6 +147,12 @@
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 @@
}
/**
+ * @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 fdd971b..190fc35 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 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 ee8c376..09d45d1 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -125,4 +125,10 @@
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 330dbab..fee3aa5 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -316,6 +316,12 @@
/** @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 f5f7ea3..0aa20ef 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 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 @@
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 b659135..7a4fddf 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 a7e3bec..1ae318a 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 @@
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 @@
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 4a6fb13..34acebf 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -728,10 +728,7 @@
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 @@
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 @@
// 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 @@
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 6ff0c5a..6a064d2 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.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 c7982b1..78d16d9 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.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 a30b362..9f7261d 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 @@
@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 @@
@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 @@
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 d7f4a38..89bd8d8 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 @@
@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 8dd176d..a3404e5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@
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 1d414743..3eef7aa7 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -41,6 +41,8 @@
return "dimen";
case ResourceType::kDrawable:
return "drawable";
+ case ResourceType::kFont:
+ return "font";
case ResourceType::kFraction:
return "fraction";
case ResourceType::kId:
@@ -83,6 +85,7 @@
{"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 78acb70..13330b5 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -46,6 +46,7 @@
kColor,
kDimen,
kDrawable,
+ kFont,
kFraction,
kId,
kInteger,
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 720ab91..6acb4d3 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -57,6 +57,10 @@
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 a06140c..f0b18e6 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -482,7 +482,9 @@
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 f1bc53e..7ab05b5 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -232,6 +232,13 @@
}
}*/
+#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 01c9adb..aff1da3 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -62,8 +62,8 @@
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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..1fb6791
--- /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 68db6b3..0d0e46d 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -361,7 +361,7 @@
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 @@
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 93c790d..ac411b1 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 eb52b64..819103d 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 57d08cb..fbaed52 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 e1fc5ec..2ae4654 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 @@
@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 @@
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 4a4c6c8..94152cd 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 @@
// ---- 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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 a503e50..354f919 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 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 @@
// ---- 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 @@
// ---- 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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 33296e1..0bbe33d 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 @@
// ---- 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 @@
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 3e81e83..9904263 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 e4cbb2f..3471165 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 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 a0b2977..1b3b563 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 @@
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 b3ed9e1..0b169bd 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 @@
}
@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 0000000..e69de29
--- /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 4561e1b..4781660 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 @@
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 @@
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
index e0373cb..f73528a 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
Binary files differ
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
deleted file mode 100644
index c363055..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index edda3de..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
+++ /dev/null
Binary files differ
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
index ec42017..5bb04fc 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
Binary files differ
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
new file mode 100644
index 0000000..ff699d1
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class
Binary files differ
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
index 0e208f2..a3931b8 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
Binary files differ
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
index 2b77af3..e293677 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
Binary files differ
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
index fd01b44..d6268bf 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
Binary files differ
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
index 91cf5b6..08b98fb 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
Binary files differ
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
index 6c351da..f9be1ca 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
Binary files differ
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
index aecbff6..6874b49e 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
Binary files differ
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
index fc3f236..a4205a8 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
Binary files differ
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
index 83ad35b..4fb3b61 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
Binary files differ
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
index 6d7c719..dba67fd 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
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 9bf302a..f274dbf 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
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 41d75de..e7f22bf 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/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
deleted file mode 100644
index 80bbaf1..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.layoutlib.test.myapplication;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.CalendarView;
-
-public class CustomCalendar extends CalendarView {
- public CustomCalendar(Context context) {
- super(context);
- init();
- }
-
- public CustomCalendar(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- private void init() {
- setDate(871703200000L, 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/java/com/android/layoutlib/test/myapplication/CustomDate.java
deleted file mode 100644
index cb750f4..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.layoutlib.test.myapplication;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.DatePicker;
-
-public class CustomDate extends DatePicker {
- public CustomDate(Context context) {
- super(context);
- init();
- }
-
- public CustomDate(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public CustomDate(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- public CustomDate(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- private void init() {
- init(2015, 0, 20, null);
- }
-}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java
new file mode 100644
index 0000000..3b819e5
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.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.layoutlib.test.myapplication.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.CalendarView;
+
+public class CustomCalendar extends CalendarView {
+ public CustomCalendar(Context context) {
+ super(context);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ setDate(871732800000L, false, true);
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java
new file mode 100644
index 0000000..f3877f1
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.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.layoutlib.test.myapplication.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.DatePicker;
+
+public class CustomDate extends DatePicker {
+ public CustomDate(Context context) {
+ super(context);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ init(2015, 0, 20, null);
+ }
+}
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 0000000..58ad46d
--- /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 50646ab..e9aa9e1 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 c1f663e..ff14ce0 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 88c9cbc..c8a5fec 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 e7c6cc9..5423e87 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.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 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 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 @@
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 @@
/** 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 @@
}
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 @@
// 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 @@
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 @@
/** 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
@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 @@
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 @@
// 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 96ae523..bae2dc0c 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.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 @@
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 110f4c8..0000000
--- 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 ce877b3..09d95ff 100644
--- a/tools/preload2/Android.mk
+++ b/tools/preload2/Android.mk
@@ -5,7 +5,7 @@
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 0000000..b5f7c94
--- /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 017525b..9e897bf 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 @@
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 @@
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 465addf..da87135 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -66,6 +66,93 @@
* 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 8d5efba..e48f7bdb 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -22,6 +22,7 @@
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 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 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 @@
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 @@
txSuccess = txgood;
rxSuccess = rxgood;
txRetries = txretries;
+ mLastPacketCountUpdateTimeStamp = timeStamp;
} else {
txBad = 0;
txSuccess = 0;
@@ -200,6 +220,7 @@
txSuccessRate = 0;
rxSuccessRate = 0;
txRetriesRate = 0;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
}
@@ -243,6 +264,7 @@
mRssi = INVALID_RSSI;
mLinkSpeed = -1;
mFrequency = -1;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
/** @hide */
@@ -268,6 +290,7 @@
badRssiCount = 0;
linkStuckCount = 0;
score = 0;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
/**
@@ -295,6 +318,8 @@
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 18a580e..674c161 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -26,6 +26,7 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 5d3ad058..ba493a0 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -32,9 +32,8 @@
/**
* 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 2a6cc93..5e14f8f 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -32,9 +32,8 @@
/**
* 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 @@
* 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 2cace61..1e8dbd9 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
@@ -18,7 +18,7 @@
/**
* 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 @@
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 @@
/**
* 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 6232c14..072ccab 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
@@ -58,7 +58,8 @@
* 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 07f7523..e8335d1 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
@@ -32,10 +32,10 @@
* {@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 @@
/**
* 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 @@
/**
* 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 @@
* (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 @@
/**
* 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 @@
* {@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 @@
* [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 9dfa24f..6331c9c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
@@ -26,11 +26,10 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
* @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 @@
*
* @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 @@
/**
* 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 5528ff8..a34ef47 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -56,14 +56,14 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* {@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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
}
/** @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 @@
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 @@
}
/** @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 @@
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 @@
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 @@
}
}
- /** @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 610a92c..68786d1 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
@@ -21,9 +21,8 @@
/**
* 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 357bd43..acb60a4 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -65,7 +65,7 @@
* 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 @@
* <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 @@
* <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 @@
* 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 7c48f54..a0ec809 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
@@ -21,8 +21,8 @@
/**
* 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 0000000..96db5d0
--- /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 18aae53..643753a 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -36,6 +36,27 @@
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 @@
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 92dbd8a..790dfaf 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 @@
* @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 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 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 @@
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 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 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 @@
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 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 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 @@
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 @@
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 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 @@
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 @@
}
};
+ /**
+ * 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 @@
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 2acc8be..d4a5792 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 @@
import android.os.Parcelable;
import android.os.Parcel;
import android.text.TextUtils;
+import android.util.Log;
import java.util.Arrays;
@@ -34,6 +35,8 @@
* @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 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 @@
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 ee2e895..8b1cfae 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -28,5 +28,6 @@
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 398308d..c93ac7b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1324,6 +1324,11 @@
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 0000000..8c1eb08
--- /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 0000000..6d86dd5
--- /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 0000000..906bfb3
--- /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 0000000..3fa97d1
--- /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 0000000..975f8e5
--- /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 0000000..833c527
--- /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 0000000..d1f8384
--- /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 0000000..6095929
--- /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 be11f0e..2350d32 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 @@
@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 @@
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 @@
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 @@
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 @@
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 68ac4ef..9c8b749 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 @@
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 @@
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 @@
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 0d2da64..c707993 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 @@
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));
+ }
}