summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt20
-rw-r--r--api/system-current.txt20
-rw-r--r--core/java/android/app/ActivityThread.java9
-rw-r--r--core/java/android/app/FragmentManager.java1
-rw-r--r--core/java/android/app/LoadedApk.java7
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java3
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java8
-rw-r--r--core/java/android/content/res/Configuration.java210
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java43
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl4
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl28
-rw-r--r--core/java/android/hardware/input/InputManager.java1
-rw-r--r--core/java/android/os/BatteryStats.java1
-rw-r--r--core/java/android/os/Trace.java2
-rw-r--r--core/java/android/util/LocaleList.java111
-rw-r--r--core/java/android/view/HandlerActionQueue.java127
-rw-r--r--core/java/android/view/IWindowManager.aidl10
-rw-r--r--core/java/android/view/View.java86
-rw-r--r--core/java/android/view/ViewRootImpl.java82
-rw-r--r--core/java/android/widget/ActionMenuPresenter.java6
-rw-r--r--core/java/android/widget/ActivityChooserView.java4
-rw-r--r--core/java/android/widget/DropDownListView.java344
-rw-r--r--core/java/android/widget/ForwardingListener.java299
-rw-r--r--core/java/android/widget/ListPopupWindow.java581
-rw-r--r--core/java/android/widget/MenuPopupWindow.java4
-rw-r--r--core/java/android/widget/PopupMenu.java4
-rw-r--r--core/java/android/widget/Spinner.java4
-rw-r--r--core/java/android/widget/TextView.java50
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java2
-rw-r--r--core/java/com/android/internal/os/CpuPowerCalculator.java51
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java88
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItemView.java10
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuItemView.java16
-rw-r--r--core/java/com/android/internal/view/menu/MenuAdapter.java109
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java71
-rw-r--r--core/java/com/android/internal/view/menu/ShowableListMenu.java35
-rw-r--r--core/java/com/android/internal/widget/AbsActionBarView.java55
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java13
-rw-r--r--core/jni/AndroidRuntime.cpp3
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp10
-rw-r--r--core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml34
-rw-r--r--core/res/res/layout/popup_menu_item_layout.xml9
-rw-r--r--core/res/res/values-ca-watch/strings.xml6
-rw-r--r--core/res/res/values-el-watch/strings.xml2
-rw-r--r--core/res/res/values-eu-rES-watch/strings.xml2
-rw-r--r--core/res/res/values-ml-rIN/strings.xml2
-rw-r--r--core/res/res/values-ne-rNP-watch/strings.xml2
-rw-r--r--core/res/res/values-ta-rIN-watch/strings.xml2
-rw-r--r--core/res/res/values-ur-rPK/strings.xml2
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/res/res/values/styles_material.xml4
-rwxr-xr-xcore/res/res/values/symbols.xml1
-rw-r--r--core/res/res/values/themes_material.xml2
-rw-r--r--core/tests/coretests/src/android/view/HandlerActionQueueTest.java80
-rw-r--r--graphics/java/android/graphics/Paint.java88
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java511
-rw-r--r--libs/androidfw/Android.mk6
-rw-r--r--media/java/android/mtp/MtpObjectInfo.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CopyService.java42
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java16
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java16
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java100
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java55
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java2
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java132
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java67
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java43
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java19
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java24
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java68
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java9
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java89
-rw-r--r--packages/SystemUI/res/values-af/strings.xml4
-rw-r--r--packages/SystemUI/res/values-am/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml4
-rw-r--r--packages/SystemUI/res/values-az-rAZ/strings.xml4
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml4
-rw-r--r--packages/SystemUI/res/values-bn-rBD/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml4
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml4
-rw-r--r--packages/SystemUI/res/values-da/strings.xml4
-rw-r--r--packages/SystemUI/res/values-de/strings.xml4
-rw-r--r--packages/SystemUI/res/values-el/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml4
-rw-r--r--packages/SystemUI/res/values-es/strings.xml4
-rw-r--r--packages/SystemUI/res/values-et-rEE/strings.xml4
-rw-r--r--packages/SystemUI/res/values-eu-rES/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-gl-rES/strings.xml4
-rw-r--r--packages/SystemUI/res/values-gu-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hy-rAM/strings.xml4
-rw-r--r--packages/SystemUI/res/values-in/strings.xml4
-rw-r--r--packages/SystemUI/res/values-is-rIS/strings.xml4
-rw-r--r--packages/SystemUI/res/values-it/strings.xml4
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ka-rGE/strings.xml4
-rw-r--r--packages/SystemUI/res/values-kk-rKZ/strings.xml4
-rw-r--r--packages/SystemUI/res/values-km-rKH/strings.xml4
-rw-r--r--packages/SystemUI/res/values-kn-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ky-rKG/strings.xml4
-rw-r--r--packages/SystemUI/res/values-lo-rLA/strings.xml4
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml4
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml4
-rw-r--r--packages/SystemUI/res/values-mk-rMK/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ml-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-mn-rMN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-mr-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ms-rMY/strings.xml4
-rw-r--r--packages/SystemUI/res/values-my-rMM/strings.xml4
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ne-rNP/strings.xml4
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pa-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml6
-rw-r--r--packages/SystemUI/res/values-si-rLK/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sq-rAL/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ta-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-te-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-th/strings.xml4
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ur-rPK/strings.xml4
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml4
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml4
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml4
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml4
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java6
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java2
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java98
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java46
-rw-r--r--services/core/java/com/android/server/am/LaunchingTaskPositioner.java3
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java98
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java70
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java17
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java232
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java5
-rw-r--r--services/core/java/com/android/server/wm/Task.java87
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java32
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java47
-rw-r--r--services/java/com/android/server/SystemServer.java335
-rw-r--r--telecomm/java/android/telecom/Call.java8
-rw-r--r--telecomm/java/android/telecom/Connection.java20
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java23
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java10
-rw-r--r--tests/SurfaceComposition/Android.mk34
-rw-r--r--tests/SurfaceComposition/AndroidManifest.xml36
-rw-r--r--tests/SurfaceComposition/res/values/themes.xml25
-rw-r--r--tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java48
-rw-r--r--tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java243
-rw-r--r--tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java71
-rw-r--r--tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java602
-rw-r--r--tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java81
-rw-r--r--tests/UiBench/AndroidManifest.xml36
-rw-r--r--tests/UiBench/res/layout/card_row.xml45
-rw-r--r--tests/UiBench/src/com/android/test/uibench/DialogListActivity.java38
-rw-r--r--tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java50
-rw-r--r--tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java45
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java2
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java51
-rw-r--r--tools/aapt/Android.mk51
-rw-r--r--tools/aidl/AST.h6
-rw-r--r--tools/aidl/Android.mk68
-rw-r--r--tools/aidl/Type.h6
-rw-r--r--tools/aidl/aidl.cpp30
-rw-r--r--tools/aidl/aidl.h9
-rw-r--r--tools/aidl/aidl_language.h6
-rw-r--r--tools/aidl/generate_java.h6
-rw-r--r--tools/aidl/main.cpp23
-rw-r--r--tools/aidl/options.cpp4
-rw-r--r--tools/aidl/options.h12
-rw-r--r--tools/aidl/options_unittest.cpp54
-rw-r--r--tools/aidl/os.h6
-rw-r--r--tools/aidl/search_path.h7
-rw-r--r--tools/aidl/test_main.cpp6
-rw-r--r--tools/aidl/tests/test.cpp3
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java9
-rw-r--r--tools/split-select/Android.mk39
211 files changed, 5033 insertions, 2256 deletions
diff --git a/Android.mk b/Android.mk
index 40da13478ec8..e84b6837ff19 100644
--- a/Android.mk
+++ b/Android.mk
@@ -160,6 +160,7 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+ core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
diff --git a/api/current.txt b/api/current.txt
index e9c5727e1027..1eb37b3a45c4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -241,10 +241,10 @@ package android {
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
- field public static final int activityHeight = 16844019; // 0x10104f3
+ field public static final int activityHeight = 16844021; // 0x10104f5
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
- field public static final int activityWidth = 16844018; // 0x10104f2
+ field public static final int activityWidth = 16844020; // 0x10104f4
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -786,6 +786,7 @@ package android {
field public static final int listChoiceIndicatorSingle = 16843289; // 0x1010219
field public static final int listDivider = 16843284; // 0x1010214
field public static final int listDividerAlertDialog = 16843525; // 0x1010305
+ field public static final int listMenuViewStyle = 16844018; // 0x10104f2
field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
field public static final int listPreferredItemHeight = 16842829; // 0x101004d
field public static final int listPreferredItemHeightLarge = 16843654; // 0x1010386
@@ -1148,6 +1149,7 @@ package android {
field public static final int strokeLineJoin = 16843788; // 0x101040c
field public static final int strokeMiterLimit = 16843789; // 0x101040d
field public static final int strokeWidth = 16843783; // 0x1010407
+ field public static final int subMenuArrow = 16844019; // 0x10104f3
field public static final int submitBackground = 16843912; // 0x1010488
field public static final int subtitle = 16843473; // 0x10102d1
field public static final int subtitleTextAppearance = 16843823; // 0x101042f
@@ -9663,12 +9665,14 @@ package android.content.res {
method public int diff(android.content.res.Configuration);
method public boolean equals(android.content.res.Configuration);
method public int getLayoutDirection();
+ method public android.util.LocaleList getLocales();
method public boolean isLayoutSizeAtLeast(int);
method public boolean isScreenRound();
method public static boolean needNewResources(int, int);
method public void readFromParcel(android.os.Parcel);
method public void setLayoutDirection(java.util.Locale);
method public void setLocale(java.util.Locale);
+ method public void setLocales(android.util.LocaleList);
method public void setTo(android.content.res.Configuration);
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
@@ -9742,7 +9746,7 @@ package android.content.res {
field public int hardKeyboardHidden;
field public int keyboard;
field public int keyboardHidden;
- field public java.util.Locale locale;
+ field public deprecated java.util.Locale locale;
field public int mcc;
field public int mnc;
field public int navigation;
@@ -11586,6 +11590,7 @@ package android.graphics {
method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
method public void getTextBounds(char[], int, int, android.graphics.Rect);
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
method public float getTextScaleX();
@@ -11641,6 +11646,7 @@ package android.graphics {
method public void setSubpixelText(boolean);
method public void setTextAlign(android.graphics.Paint.Align);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSkewX(float);
@@ -18164,6 +18170,7 @@ package android.mtp {
method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+ method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -34200,11 +34207,16 @@ package android.util {
public final class LocaleList {
ctor public LocaleList();
+ ctor public LocaleList(java.util.Locale);
ctor public LocaleList(java.util.Locale[]);
+ method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getDefault();
+ method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
+ method public java.lang.String toLanguageTags();
}
public final class Log {
@@ -41712,6 +41724,7 @@ package android.widget {
method public java.lang.CharSequence getText();
method public final android.content.res.ColorStateList getTextColors();
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public float getTextScaleX();
method public float getTextSize();
method public int getTotalPaddingBottom();
@@ -41824,6 +41837,7 @@ package android.widget {
method public final void setTextKeepState(java.lang.CharSequence);
method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSize(int, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index e234970b9c80..f913e6c99b2c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -333,10 +333,10 @@ package android {
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
- field public static final int activityHeight = 16844019; // 0x10104f3
+ field public static final int activityHeight = 16844021; // 0x10104f5
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
- field public static final int activityWidth = 16844018; // 0x10104f2
+ field public static final int activityWidth = 16844020; // 0x10104f4
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -878,6 +878,7 @@ package android {
field public static final int listChoiceIndicatorSingle = 16843289; // 0x1010219
field public static final int listDivider = 16843284; // 0x1010214
field public static final int listDividerAlertDialog = 16843525; // 0x1010305
+ field public static final int listMenuViewStyle = 16844018; // 0x10104f2
field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
field public static final int listPreferredItemHeight = 16842829; // 0x101004d
field public static final int listPreferredItemHeightLarge = 16843654; // 0x1010386
@@ -1244,6 +1245,7 @@ package android {
field public static final int strokeLineJoin = 16843788; // 0x101040c
field public static final int strokeMiterLimit = 16843789; // 0x101040d
field public static final int strokeWidth = 16843783; // 0x1010407
+ field public static final int subMenuArrow = 16844019; // 0x10104f3
field public static final int submitBackground = 16843912; // 0x1010488
field public static final int subtitle = 16843473; // 0x10102d1
field public static final int subtitleTextAppearance = 16843823; // 0x101042f
@@ -10000,12 +10002,14 @@ package android.content.res {
method public int diff(android.content.res.Configuration);
method public boolean equals(android.content.res.Configuration);
method public int getLayoutDirection();
+ method public android.util.LocaleList getLocales();
method public boolean isLayoutSizeAtLeast(int);
method public boolean isScreenRound();
method public static boolean needNewResources(int, int);
method public void readFromParcel(android.os.Parcel);
method public void setLayoutDirection(java.util.Locale);
method public void setLocale(java.util.Locale);
+ method public void setLocales(android.util.LocaleList);
method public void setTo(android.content.res.Configuration);
method public void setToDefaults();
method public int updateFrom(android.content.res.Configuration);
@@ -10079,7 +10083,7 @@ package android.content.res {
field public int hardKeyboardHidden;
field public int keyboard;
field public int keyboardHidden;
- field public java.util.Locale locale;
+ field public deprecated java.util.Locale locale;
field public int mcc;
field public int mnc;
field public int navigation;
@@ -11923,6 +11927,7 @@ package android.graphics {
method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
method public void getTextBounds(char[], int, int, android.graphics.Rect);
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
method public float getTextScaleX();
@@ -11978,6 +11983,7 @@ package android.graphics {
method public void setSubpixelText(boolean);
method public void setTextAlign(android.graphics.Paint.Align);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSkewX(float);
@@ -19676,6 +19682,7 @@ package android.mtp {
method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+ method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
method public android.mtp.MtpObjectInfo.Builder setParent(int);
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -36494,11 +36501,16 @@ package android.util {
public final class LocaleList {
ctor public LocaleList();
+ ctor public LocaleList(java.util.Locale);
ctor public LocaleList(java.util.Locale[]);
+ method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getDefault();
+ method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getPrimary();
method public boolean isEmpty();
method public int size();
+ method public java.lang.String toLanguageTags();
}
public final class Log {
@@ -44320,6 +44332,7 @@ package android.widget {
method public java.lang.CharSequence getText();
method public final android.content.res.ColorStateList getTextColors();
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public float getTextScaleX();
method public float getTextSize();
method public int getTotalPaddingBottom();
@@ -44432,6 +44445,7 @@ package android.widget {
method public final void setTextKeepState(java.lang.CharSequence);
method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSize(int, float);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 412e3cde902c..e15ba742b8b6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4718,7 +4718,13 @@ public final class ActivityThread {
mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
mInstrumentedLibDir = data.info.getLibDir();
- ApplicationInfo instrApp = new ApplicationInfo();
+ // The app context's info was created against this thread, but
+ // the class loader may have already been loaded and cached with
+ // outdated paths. Clear it so we can load it again using the
+ // instrumentation paths.
+ data.info.clearClassLoader();
+
+ final ApplicationInfo instrApp = new ApplicationInfo();
instrApp.packageName = ii.packageName;
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
@@ -4731,6 +4737,7 @@ public final class ActivityThread {
ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
+
java.lang.ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3b026d26b757..132ffef861e6 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2196,6 +2196,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
fragment.mTag = tag;
fragment.mInLayout = true;
fragment.mFragmentManager = this;
+ fragment.mHost = mHost;
fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
addFragment(fragment, true);
} else if (fragment.mInLayout) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c2bf28a931c8..3b1c60b1501f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -255,6 +255,13 @@ public final class LoadedApk {
return ai.sharedLibraryFiles;
}
+ /** @hide */
+ public void clearClassLoader() {
+ synchronized (this) {
+ mClassLoader = null;
+ }
+ }
+
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader != null) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e3414d916337..7ffac0a6dc39 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -213,7 +213,8 @@ public class DevicePolicyManager {
* @see DeviceAdminReceiver
* @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
- * supported.
+ * supported, but only if there is only one device admin receiver in the package that requires
+ * the permission {@link android.Manifest.permission#BIND_DEVICE_ADMIN}.
*/
@Deprecated
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6feb86036791..914945b2f64a 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -531,12 +531,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* String retrieved from the seinfo tag found in selinux policy. This value
- * is useful in setting an SELinux security context on the process as well
- * as its data directory.
+ * can be overridden with a value set through the mac_permissions.xml policy
+ * construct. This value is useful in setting an SELinux security context on
+ * the process as well as its data directory. The String default is being used
+ * here to represent a catchall label when no policy matches.
*
* {@hide}
*/
- public String seinfo;
+ public String seinfo = "default";
/**
* Paths to all shared libraries this application is linked against. This
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fd6047684eb5..3ecbaa05a4f1 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -22,11 +22,13 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.LocaleList;
import android.view.View;
import java.io.IOException;
@@ -36,7 +38,7 @@ import java.util.Locale;
/**
* This class describes all device configuration information that can
* impact the resources the application retrieves. This includes both
- * user-specified configuration options (locale and scaling) as well
+ * user-specified configuration options (locale list and scaling) as well
* as device configurations (such as input modes, screen size and screen orientation).
* <p>You can acquire this object from {@link Resources}, using {@link
* Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
@@ -78,8 +80,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* Current user preference for the locale, corresponding to
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
* resource qualifier.
+ *
+ * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
+ * {@link #setLocales(LocaleList)}.
*/
- public Locale locale;
+ @Deprecated public Locale locale;
+
+ private LocaleList mLocaleList;
/**
* Locale should persist on setting. This is hidden because it is really
@@ -648,6 +655,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
setTo(o);
}
+ /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
+ * about setLocales() has changed locale directly. */
+ private void fixUpLocaleList() {
+ if ((locale == null && !mLocaleList.isEmpty()) ||
+ (locale != null && !locale.equals(mLocaleList.getPrimary()))) {
+ mLocaleList = new LocaleList(locale);
+ }
+ }
+
public void setTo(Configuration o) {
fontScale = o.fontScale;
mcc = o.mcc;
@@ -655,6 +671,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (o.locale != null) {
locale = (Locale) o.locale.clone();
}
+ o.fixUpLocaleList();
+ mLocaleList = o.mLocaleList;
userSetLocale = o.userSetLocale;
touchscreen = o.touchscreen;
keyboard = o.keyboard;
@@ -692,11 +710,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
} else {
sb.append("?mnc");
}
- if (locale != null) {
+ fixUpLocaleList();
+ if (!mLocaleList.isEmpty()) {
sb.append(" ");
- sb.append(locale);
+ sb.append(mLocaleList);
} else {
- sb.append(" ?locale");
+ sb.append(" ?localeList");
}
int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
switch (layoutDir) {
@@ -819,6 +838,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public void setToDefaults() {
fontScale = 1;
mcc = mnc = 0;
+ mLocaleList = LocaleList.getEmptyLocaleList();
locale = null;
userSetLocale = false;
touchscreen = TOUCHSCREEN_UNDEFINED;
@@ -864,16 +884,20 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_MNC;
mnc = delta.mnc;
}
- if (delta.locale != null
- && (locale == null || !locale.equals(delta.locale))) {
+ fixUpLocaleList();
+ delta.fixUpLocaleList();
+ if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
changed |= ActivityInfo.CONFIG_LOCALE;
- locale = delta.locale != null
- ? (Locale) delta.locale.clone() : null;
- // If locale has changed, then layout direction is also changed ...
- changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
- // ... and we need to update the layout direction (represented by the first
- // 2 most significant bits in screenLayout).
- setLayoutDirection(locale);
+ mLocaleList = delta.mLocaleList;
+ // delta.locale can't be null, since delta.mLocaleList is not empty.
+ if (!delta.locale.equals(locale)) {
+ locale = (Locale) delta.locale.clone();
+ // If locale has changed, then layout direction is also changed ...
+ changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+ // ... and we need to update the layout direction (represented by the first
+ // 2 most significant bits in screenLayout).
+ setLayoutDirection(locale);
+ }
}
final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
@@ -1023,8 +1047,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (delta.mnc != 0 && mnc != delta.mnc) {
changed |= ActivityInfo.CONFIG_MNC;
}
- if (delta.locale != null
- && (locale == null || !locale.equals(delta.locale))) {
+ fixUpLocaleList();
+ delta.fixUpLocaleList();
+ if (!mLocaleList.equals(delta.mLocaleList)) {
changed |= ActivityInfo.CONFIG_LOCALE;
changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
}
@@ -1146,14 +1171,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeFloat(fontScale);
dest.writeInt(mcc);
dest.writeInt(mnc);
- if (locale == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(1);
- dest.writeString(locale.getLanguage());
- dest.writeString(locale.getCountry());
- dest.writeString(locale.getVariant());
+
+ fixUpLocaleList();
+ final int localeListSize = mLocaleList.size();
+ dest.writeInt(localeListSize);
+ for (int i = 0; i < localeListSize; ++i) {
+ final Locale l = mLocaleList.get(i);
+ dest.writeString(l.toLanguageTag());
}
+
if(userSetLocale) {
dest.writeInt(1);
} else {
@@ -1182,10 +1208,15 @@ public final class Configuration implements Parcelable, Comparable<Configuration
fontScale = source.readFloat();
mcc = source.readInt();
mnc = source.readInt();
- if (source.readInt() != 0) {
- locale = new Locale(source.readString(), source.readString(),
- source.readString());
+
+ final int localeListSize = source.readInt();
+ final Locale[] localeArray = new Locale[localeListSize];
+ for (int i = 0; i < localeListSize; ++i) {
+ localeArray[i] = Locale.forLanguageTag(source.readString());
}
+ mLocaleList = new LocaleList(localeArray);
+ locale = mLocaleList.getPrimary();
+
userSetLocale = (source.readInt()==1);
touchscreen = source.readInt();
keyboard = source.readInt();
@@ -1234,18 +1265,33 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (n != 0) return n;
n = this.mnc - that.mnc;
if (n != 0) return n;
- if (this.locale == null) {
- if (that.locale != null) return 1;
- } else if (that.locale == null) {
+
+ fixUpLocaleList();
+ that.fixUpLocaleList();
+ // for backward compatibility, we consider an empty locale list to be greater
+ // than any non-empty locale list.
+ if (this.mLocaleList.isEmpty()) {
+ if (!that.mLocaleList.isEmpty()) return 1;
+ } else if (that.mLocaleList.isEmpty()) {
return -1;
} else {
- n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
- if (n != 0) return n;
- n = this.locale.getCountry().compareTo(that.locale.getCountry());
- if (n != 0) return n;
- n = this.locale.getVariant().compareTo(that.locale.getVariant());
+ final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
+ for (int i = 0; i < minSize; ++i) {
+ final Locale thisLocale = this.mLocaleList.get(i);
+ final Locale thatLocale = that.mLocaleList.get(i);
+ n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
+ if (n != 0) return n;
+ n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
+ if (n != 0) return n;
+ n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
+ if (n != 0) return n;
+ n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
+ if (n != 0) return n;
+ }
+ n = this.mLocaleList.size() - that.mLocaleList.size();
if (n != 0) return n;
}
+
n = this.touchscreen - that.touchscreen;
if (n != 0) return n;
n = this.keyboard - that.keyboard;
@@ -1288,13 +1334,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
return false;
}
-
+
public int hashCode() {
int result = 17;
result = 31 * result + Float.floatToIntBits(fontScale);
result = 31 * result + mcc;
result = 31 * result + mnc;
- result = 31 * result + (locale != null ? locale.hashCode() : 0);
+ result = 31 * result + mLocaleList.hashCode();
result = 31 * result + touchscreen;
result = 31 * result + keyboard;
result = 31 * result + keyboardHidden;
@@ -1312,17 +1358,50 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
/**
- * Set the locale. This is the preferred way for setting up the locale (instead of using the
- * direct accessor). This will also set the layout direction according to the locale.
+ * Get the locale list. This is the preferred way for getting the locales (instead of using
+ * the direct accessor to {@link #locale}, which would only provide the primary locale).
*
- * @param loc The locale. Can be null.
+ * @return The locale list.
+ */
+ public LocaleList getLocales() {
+ fixUpLocaleList();
+ return mLocaleList;
+ }
+
+ /**
+ * Set the locale list. This is the preferred way for setting up the locales (instead of using
+ * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
+ * according to the first locale in the list.
+ *
+ * Note that the layout direction will always come from the first locale in the locale list,
+ * even if the locale is not supported by the resources (the resources may only support
+ * another locale further down the list which has a different direction).
+ *
+ * @param locales The locale list. If null, an empty LocaleList will be assigned.
*/
- public void setLocale(Locale loc) {
- locale = loc;
+ public void setLocales(@Nullable LocaleList locales) {
+ mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
+ locale = mLocaleList.getPrimary();
setLayoutDirection(locale);
}
/**
+ * Set the locale list to a list of just one locale. This will also set the layout direction
+ * according to the locale.
+ *
+ * Note that after this is run, calling <code>.equals()</code> on the input locale and the
+ * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
+ * no guarantee that they would be the same object.
+ *
+ * See also the note about layout direction in {@link #setLocales(LocaleList)}.
+ *
+ * @param loc The locale. Can be null.
+ */
+ public void setLocale(@Nullable Locale loc) {
+ setLocales(new LocaleList(loc));
+ }
+
+ /**
* Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
* {@link View#LAYOUT_DIRECTION_RTL}.
*
@@ -1335,19 +1414,19 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
/**
- * Set the layout direction from the Locale.
+ * Set the layout direction from a Locale.
*
- * @param locale The Locale. If null will set the layout direction to
+ * @param loc The Locale. If null will set the layout direction to
* {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
* corresponding to the Locale.
*
* @see View#LAYOUT_DIRECTION_LTR
* @see View#LAYOUT_DIRECTION_RTL
*/
- public void setLayoutDirection(Locale locale) {
+ public void setLayoutDirection(Locale loc) {
// There is a "1" difference between the configuration values for
// layout direction and View constants for layout direction, just add "1".
- final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
+ final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
(layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
}
@@ -1370,21 +1449,21 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*
* @hide
*/
- public static String localeToResourceQualifier(Locale locale) {
+ public static String localeToResourceQualifier(Locale loc) {
StringBuilder sb = new StringBuilder();
- boolean l = (locale.getLanguage().length() != 0);
- boolean c = (locale.getCountry().length() != 0);
- boolean s = (locale.getScript().length() != 0);
- boolean v = (locale.getVariant().length() != 0);
-
+ boolean l = (loc.getLanguage().length() != 0);
+ boolean c = (loc.getCountry().length() != 0);
+ boolean s = (loc.getScript().length() != 0);
+ boolean v = (loc.getVariant().length() != 0);
+ // TODO: take script and extensions into account
if (l) {
- sb.append(locale.getLanguage());
+ sb.append(loc.getLanguage());
if (c) {
- sb.append("-r").append(locale.getCountry());
+ sb.append("-r").append(loc.getCountry());
if (s) {
- sb.append("-s").append(locale.getScript());
+ sb.append("-s").append(loc.getScript());
if (v) {
- sb.append("-v").append(locale.getVariant());
+ sb.append("-v").append(loc.getVariant());
}
}
}
@@ -1409,6 +1488,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
}
+ // TODO: send the whole locale list
if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
parts.add(localeToResourceQualifier(config.locale));
}
@@ -1646,8 +1726,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
delta.mnc = change.mnc;
}
- if ((base.locale == null && change.locale != null) ||
- (base.locale != null && !base.locale.equals(change.locale))) {
+ base.fixUpLocaleList();
+ change.fixUpLocaleList();
+ if (!base.mLocaleList.equals(change.mLocaleList)) {
+ delta.mLocaleList = change.mLocaleList;
delta.locale = change.locale;
}
@@ -1724,7 +1806,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
private static final String XML_ATTR_FONT_SCALE = "fs";
private static final String XML_ATTR_MCC = "mcc";
private static final String XML_ATTR_MNC = "mnc";
- private static final String XML_ATTR_LOCALE = "locale";
+ private static final String XML_ATTR_LOCALES = "locales";
private static final String XML_ATTR_TOUCHSCREEN = "touch";
private static final String XML_ATTR_KEYBOARD = "key";
private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
@@ -1754,10 +1836,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
- final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE);
- if (localeStr != null) {
- configOut.locale = Locale.forLanguageTag(localeStr);
- }
+ final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
+ configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
+ configOut.locale = configOut.mLocaleList.getPrimary();
configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
TOUCHSCREEN_UNDEFINED);
@@ -1807,8 +1888,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (config.mnc != 0) {
XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc);
}
- if (config.locale != null) {
- XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag());
+ config.fixUpLocaleList();
+ if (!config.mLocaleList.isEmpty()) {
+ XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags());
}
if (config.touchscreen != TOUCHSCREEN_UNDEFINED) {
XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7cff11b01383..1f23c0a6ba3f 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -392,6 +392,18 @@ public class FingerprintManager {
};
/**
+ * @hide
+ */
+ public static abstract class LockoutResetCallback {
+
+ /**
+ * Called when lockout period expired and clients are allowed to listen for fingerprint
+ * again.
+ */
+ public void onLockoutReset() { }
+ };
+
+ /**
* Request authentication of a crypto object. This call warms up the fingerprint hardware
* and starts scanning for a fingerprint. It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
@@ -680,10 +692,37 @@ public class FingerprintManager {
try {
mService.resetTimeout(token);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+ Log.v(TAG, "Remote exception in resetTimeout(): ", e);
}
} else {
- Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+ Log.w(TAG, "resetTimeout(): Service not connected!");
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void addLockoutResetCallback(final LockoutResetCallback callback) {
+ if (mService != null) {
+ try {
+ mService.addLockoutResetCallback(
+ new IFingerprintServiceLockoutResetCallback.Stub() {
+
+ @Override
+ public void onLockoutReset(long deviceId) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onLockoutReset();
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+ }
+ } else {
+ Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
}
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 33563549b2ba..690a7519a3b5 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@ package android.hardware.fingerprint;
import android.os.Bundle;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
import java.util.List;
@@ -71,4 +72,7 @@ interface IFingerprintService {
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetTimeout(in byte [] cryptoToken);
+
+ // Add a callback which gets notified when the fingerprint lockout period expired.
+ void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
new file mode 100644
index 000000000000..c9a5d59874f2
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.hardware.fingerprint;
+
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Callback when lockout period expired and clients are allowed to authenticate again.
+ * @hide
+ */
+oneway interface IFingerprintServiceLockoutResetCallback {
+ void onLockoutReset(long deviceId);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 444f0201b448..42920509b283 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -291,6 +291,7 @@ public final class InputManager {
}
synchronized (mInputDevicesLock) {
+ populateInputDevicesLocked();
int index = findInputDeviceListenerLocked(listener);
if (index < 0) {
mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4ad9d6dc913e..bad94fce20aa 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -468,6 +468,7 @@ public abstract class BatteryStats implements Parcelable {
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @see BatteryStats#getCpuSpeedSteps()
*/
+ @Deprecated
public abstract long getTimeAtCpuSpeed(int step, int which);
public static abstract class Sensor {
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 4da88ee9da9c..7529c5294541 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -77,6 +77,8 @@ public final class Trace {
public static final long TRACE_TAG_POWER = 1L << 17;
/** @hide */
public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
+ /** @hide */
+ public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 017735ac03df..379651ef86f8 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -16,15 +16,19 @@
package android.util;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Size;
+
+import com.android.internal.annotations.GuardedBy;
import java.util.HashSet;
import java.util.Locale;
// TODO: We don't except too many LocaleLists to exist at the same time, and
// we need access to the data at native level, so we should pass the data
-// down to the native level, create a mapt of every list seen there, take a
-// pointer back, and just keep that pointed in the Java-level object, so
+// down to the native level, create a map of every list seen there, take a
+// pointer back, and just keep that pointer in the Java-level object, so
// things could be copied very quickly.
/**
@@ -34,6 +38,7 @@ import java.util.Locale;
public final class LocaleList {
private final Locale[] mList;
private static final Locale[] sEmptyList = new Locale[0];
+ private static final LocaleList sEmptyLocaleList = new LocaleList();
public Locale get(int location) {
return location < mList.length ? mList[location] : null;
@@ -51,6 +56,60 @@ public final class LocaleList {
return mList.length;
}
+ @Override
+ public boolean equals(Object other) {
+ if (other == this)
+ return true;
+ if (!(other instanceof LocaleList))
+ return false;
+ final Locale[] otherList = ((LocaleList) other).mList;
+ if (mList.length != otherList.length)
+ return false;
+ for (int i = 0; i < mList.length; ++i) {
+ if (!mList[i].equals(otherList[i]))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ for (int i = 0; i < mList.length; ++i) {
+ result = 31 * result + mList[i].hashCode();
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (int i = 0; i < mList.length; ++i) {
+ sb.append(mList[i]);
+ if (i < mList.length - 1) {
+ sb.append(',');
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public String toLanguageTags() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < mList.length; ++i) {
+ sb.append(mList[i].toLanguageTag());
+ if (i < mList.length - 1) {
+ sb.append(',');
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * It is almost always better to call {@link #getEmptyLocaleList()} instead which returns
+ * a pre-constructed empty locale list.
+ */
public LocaleList() {
mList = sEmptyList;
}
@@ -59,6 +118,19 @@ public final class LocaleList {
* @throws NullPointerException if any of the input locales is <code>null</code>.
* @throws IllegalArgumentException if any of the input locales repeat.
*/
+ public LocaleList(@Nullable Locale locale) {
+ if (locale == null) {
+ mList = sEmptyList;
+ } else {
+ mList = new Locale[1];
+ mList[0] = (Locale) locale.clone();
+ }
+ }
+
+ /**
+ * @throws NullPointerException if any of the input locales is <code>null</code>.
+ * @throws IllegalArgumentException if any of the input locales repeat.
+ */
public LocaleList(@Nullable Locale[] list) {
if (list == null || list.length == 0) {
mList = sEmptyList;
@@ -79,4 +151,39 @@ public final class LocaleList {
mList = localeList;
}
}
+
+ public static LocaleList getEmptyLocaleList() {
+ return sEmptyLocaleList;
+ }
+
+ public static LocaleList forLanguageTags(@Nullable String list) {
+ if (list == null || list.equals("")) {
+ return getEmptyLocaleList();
+ } else {
+ final String[] tags = list.split(",");
+ final Locale[] localeArray = new Locale[tags.length];
+ for (int i = 0; i < localeArray.length; ++i) {
+ localeArray[i] = Locale.forLanguageTag(tags[i]);
+ }
+ return new LocaleList(localeArray);
+ }
+ }
+
+ private final static Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static LocaleList sDefaultLocaleList;
+
+ // TODO: fix this to return the default system locale list once we have that
+ @NonNull @Size(min=1)
+ public static LocaleList getDefault() {
+ Locale defaultLocale = Locale.getDefault();
+ synchronized (sLock) {
+ if (sDefaultLocaleList == null || sDefaultLocaleList.size() != 1
+ || !defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
+ sDefaultLocaleList = new LocaleList(defaultLocale);
+ }
+ }
+ return sDefaultLocaleList;
+ }
}
diff --git a/core/java/android/view/HandlerActionQueue.java b/core/java/android/view/HandlerActionQueue.java
new file mode 100644
index 000000000000..4758a3408dc2
--- /dev/null
+++ b/core/java/android/view/HandlerActionQueue.java
@@ -0,0 +1,127 @@
+/*
+ * 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.view;
+
+import com.android.internal.util.GrowingArrayUtils;
+
+import android.os.Handler;
+
+import java.util.ArrayList;
+
+/**
+ * Class used to enqueue pending work from Views when no Handler is attached.
+ *
+ * @hide Exposed for test framework only.
+ */
+public class HandlerActionQueue {
+ private HandlerAction[] mActions;
+ private int mCount;
+
+ public void post(Runnable action) {
+ postDelayed(action, 0);
+ }
+
+ public void postDelayed(Runnable action, long delayMillis) {
+ final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
+
+ synchronized (this) {
+ if (mActions == null) {
+ mActions = new HandlerAction[4];
+ }
+ mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
+ mCount++;
+ }
+ }
+
+ public void removeCallbacks(Runnable action) {
+ synchronized (this) {
+ final int count = mCount;
+ int j = 0;
+
+ final HandlerAction[] actions = mActions;
+ for (int i = 0; i < count; i++) {
+ if (actions[i].matches(action)) {
+ // Remove this action by overwriting it within
+ // this loop or nulling it out later.
+ continue;
+ }
+
+ if (j != i) {
+ // At least one previous entry was removed, so
+ // this one needs to move to the "new" list.
+ actions[j] = actions[i];
+ }
+
+ j++;
+ }
+
+ // The "new" list only has j entries.
+ mCount = j;
+
+ // Null out any remaining entries.
+ for (; j < count; j++) {
+ actions[j] = null;
+ }
+ }
+ }
+
+ public void executeActions(Handler handler) {
+ synchronized (this) {
+ final HandlerAction[] actions = mActions;
+ for (int i = 0, count = mCount; i < count; i++) {
+ final HandlerAction handlerAction = actions[i];
+ handler.postDelayed(handlerAction.action, handlerAction.delay);
+ }
+
+ mActions = null;
+ mCount = 0;
+ }
+ }
+
+ public int size() {
+ return mCount;
+ }
+
+ public Runnable getRunnable(int index) {
+ if (index >= mCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mActions[index].action;
+ }
+
+ public long getDelay(int index) {
+ if (index >= mCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mActions[index].delay;
+ }
+
+ private static class HandlerAction {
+ final Runnable action;
+ final long delay;
+
+ public HandlerAction(Runnable action, long delay) {
+ this.action = action;
+ this.delay = delay;
+ }
+
+ public boolean matches(Runnable otherAction) {
+ return otherAction == null && action == null
+ || action != null && action.equals(otherAction);
+ }
+ }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f86adfe7dc01..33c51ff367c9 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -97,21 +97,21 @@ interface IWindowManager
* @param launchTaskBehind True if the token is been launched from behind.
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
- * @return The configuration of the task if it was newly created. null otherwise.
+ * @param configuration Configuration that is being used with this task.
*/
- Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+ void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds);
+ in Rect taskBounds, in Configuration configuration);
/**
*
* @param token The token we are adding to the input task Id.
* @param taskId The Id of the task we are adding the token to.
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
- * @return The configuration of the task if it was newly created. null otherwise.
+ * @param config Configuration that is being used with this task.
*/
- Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
+ void setAppTask(IBinder token, int taskId, in Rect taskBounds, in Configuration config);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 16d9bf398673..5976f0987931 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3823,6 +3823,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private static SparseArray<String> mAttributeMap;
/**
+ * Queue of pending runnables. Used to postpone calls to post() until this
+ * view is attached and has a handler.
+ */
+ private HandlerActionQueue mRunQueue;
+
+ /**
* @hide
*/
String mStartActivityRequestWho;
@@ -6681,14 +6687,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Gets the {@link View} description. It briefly describes the view and is
- * primarily used for accessibility support. Set this property to enable
- * better accessibility support for your application. This is especially
- * true for views that do not have textual representation (For example,
- * ImageButton).
- *
- * @return The content description.
+ * Returns the {@link View}'s content description.
+ * <p>
+ * <strong>Note:</strong> Do not override this method, as it will have no
+ * effect on the content description presented to accessibility services.
+ * You must call {@link #setContentDescription(CharSequence)} to modify the
+ * content description.
*
+ * @return the content description
+ * @see #setContentDescription(CharSequence)
* @attr ref android.R.styleable#View_contentDescription
*/
@ViewDebug.ExportedProperty(category = "accessibility")
@@ -6697,14 +6704,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sets the {@link View} description. It briefly describes the view and is
- * primarily used for accessibility support. Set this property to enable
- * better accessibility support for your application. This is especially
- * true for views that do not have textual representation (For example,
- * ImageButton).
+ * Sets the {@link View}'s content description.
+ * <p>
+ * A content description briefly describes the view and is primarily used
+ * for accessibility support to determine how a view should be presented to
+ * the user. In the case of a view with no textual representation, such as
+ * {@link ImageButton}, a useful content description explains what the view
+ * does. For example, an image button with a phone icon that is used to
+ * place a call may use "Call" as its content description. An image of a
+ * floppy disk that is used to save a file may use "Save".
*
* @param contentDescription The content description.
- *
+ * @see #getContentDescription()
* @attr ref android.R.styleable#View_contentDescription
*/
@RemotableViewMethod
@@ -13010,6 +13021,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Returns the queue of runnable for this view.
+ *
+ * @return the queue of runnables for this view
+ */
+ private HandlerActionQueue getRunQueue() {
+ if (mRunQueue == null) {
+ mRunQueue = new HandlerActionQueue();
+ }
+ return mRunQueue;
+ }
+
+ /**
* Gets the view root associated with the View.
* @return The view root, or null if none.
* @hide
@@ -13046,8 +13069,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().post(action);
+
+ // Postpone the runnable until we know on which thread it needs to run.
+ // Assume that the runnable will be successfully placed after attach.
+ getRunQueue().post(action);
return true;
}
@@ -13075,8 +13100,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+
+ // Postpone the runnable until we know on which thread it needs to run.
+ // Assume that the runnable will be successfully placed after attach.
+ getRunQueue().postDelayed(action, delayMillis);
return true;
}
@@ -13095,8 +13122,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
attachInfo.mViewRootImpl.mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, action, null);
} else {
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().post(action);
+ // Postpone the runnable until we know
+ // on which thread it needs to run.
+ getRunQueue().post(action);
}
}
@@ -13118,8 +13146,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
Choreographer.CALLBACK_ANIMATION, action, null, delayMillis);
} else {
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+ // Postpone the runnable until we know
+ // on which thread it needs to run.
+ getRunQueue().postDelayed(action, delayMillis);
}
}
@@ -13146,8 +13175,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, action, null);
}
- // Assume that post will succeed later
- ViewRootImpl.getRunQueue().removeCallbacks(action);
+ getRunQueue().removeCallbacks(action);
}
return true;
}
@@ -14565,7 +14593,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* this view
*/
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
- //System.out.println("Attached! " + this);
mAttachInfo = info;
if (mOverlay != null) {
mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
@@ -14581,6 +14608,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mAttachInfo.mScrollContainers.add(this);
mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
}
+ // Transfer all pending runnables.
+ if (mRunQueue != null) {
+ mRunQueue.executeActions(info.mHandler);
+ mRunQueue = null;
+ }
performCollectViewAttributes(mAttachInfo, visibility);
onAttachedToWindow();
@@ -16866,7 +16898,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
Choreographer.CALLBACK_ANIMATION, what, who,
Choreographer.subtractFrameDelay(delay));
} else {
- ViewRootImpl.getRunQueue().postDelayed(what, delay);
+ // Postpone the runnable until we know
+ // on which thread it needs to run.
+ getRunQueue().postDelayed(what, delay);
}
}
}
@@ -16884,7 +16918,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, what, who);
}
- ViewRootImpl.getRunQueue().removeCallbacks(what);
+ getRunQueue().removeCallbacks(what);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8bbaf36d4094..d26e91408666 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -28,7 +28,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
@@ -131,7 +130,7 @@ public final class ViewRootImpl implements ViewParent,
*/
static final int MAX_TRACKBALL_DELAY = 250;
- static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
+ static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
static boolean sFirstDrawComplete = false;
@@ -6759,90 +6758,17 @@ public final class ViewRootImpl implements ViewParent,
}
}
- static RunQueue getRunQueue() {
- RunQueue rq = sRunQueues.get();
+ static HandlerActionQueue getRunQueue() {
+ HandlerActionQueue rq = sRunQueues.get();
if (rq != null) {
return rq;
}
- rq = new RunQueue();
+ rq = new HandlerActionQueue();
sRunQueues.set(rq);
return rq;
}
/**
- * The run queue is used to enqueue pending work from Views when no Handler is
- * attached. The work is executed during the next call to performTraversals on
- * the thread.
- * @hide
- */
- static final class RunQueue {
- private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
-
- void post(Runnable action) {
- postDelayed(action, 0);
- }
-
- void postDelayed(Runnable action, long delayMillis) {
- HandlerAction handlerAction = new HandlerAction();
- handlerAction.action = action;
- handlerAction.delay = delayMillis;
-
- synchronized (mActions) {
- mActions.add(handlerAction);
- }
- }
-
- void removeCallbacks(Runnable action) {
- final HandlerAction handlerAction = new HandlerAction();
- handlerAction.action = action;
-
- synchronized (mActions) {
- final ArrayList<HandlerAction> actions = mActions;
-
- while (actions.remove(handlerAction)) {
- // Keep going
- }
- }
- }
-
- void executeActions(Handler handler) {
- synchronized (mActions) {
- final ArrayList<HandlerAction> actions = mActions;
- final int count = actions.size();
-
- for (int i = 0; i < count; i++) {
- final HandlerAction handlerAction = actions.get(i);
- handler.postDelayed(handlerAction.action, handlerAction.delay);
- }
-
- actions.clear();
- }
- }
-
- private static class HandlerAction {
- Runnable action;
- long delay;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- HandlerAction that = (HandlerAction) o;
- return !(action != null ? !action.equals(that.action) : that.action != null);
-
- }
-
- @Override
- public int hashCode() {
- int result = action != null ? action.hashCode() : 0;
- result = 31 * result + (int) (delay ^ (delay >>> 32));
- return result;
- }
- }
- }
-
- /**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
*/
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index a5696eefa1db..64c41039bea5 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -37,7 +37,6 @@ import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.ListPopupWindow.ForwardingListener;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.ActionMenuItemView;
import com.android.internal.view.menu.BaseMenuPresenter;
@@ -45,6 +44,7 @@ import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.MenuView;
+import com.android.internal.view.menu.ShowableListMenu;
import com.android.internal.view.menu.SubMenuBuilder;
import java.util.ArrayList;
@@ -828,7 +828,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
setOnTouchListener(new ForwardingListener(this) {
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
if (mOverflowPopup == null) {
return null;
}
@@ -1003,7 +1003,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
private class ActionMenuPopupCallback extends ActionMenuItemView.PopupCallback {
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
}
}
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index f34ad71ea76a..f5c46db94f4f 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -17,6 +17,7 @@
package android.widget;
import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
import android.annotation.StringRes;
import android.content.Context;
@@ -37,7 +38,6 @@ import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
-import android.widget.ListPopupWindow.ForwardingListener;
/**
* This class is a view for choosing an activity for handling a given {@link Intent}.
@@ -263,7 +263,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
});
expandButton.setOnTouchListener(new ForwardingListener(expandButton) {
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
return getListPopupWindow();
}
diff --git a/core/java/android/widget/DropDownListView.java b/core/java/android/widget/DropDownListView.java
new file mode 100644
index 000000000000..553651308e9c
--- /dev/null
+++ b/core/java/android/widget/DropDownListView.java
@@ -0,0 +1,344 @@
+/*
+ * 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.widget;
+
+
+import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.IntProperty;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.TextView;
+import android.widget.ListView;
+
+
+/**
+ * Wrapper class for a ListView. This wrapper can hijack the focus to
+ * make sure the list uses the appropriate drawables and states when
+ * displayed on screen within a drop down. The focus is never actually
+ * passed to the drop down in this mode; the list only looks focused.
+ *
+ * @hide
+ */
+public class DropDownListView extends ListView {
+ /** Duration in milliseconds of the drag-to-open click animation. */
+ private static final long CLICK_ANIM_DURATION = 150;
+
+ /** Target alpha value for drag-to-open click animation. */
+ private static final int CLICK_ANIM_ALPHA = 0x80;
+
+ /** Wrapper around Drawable's <code>alpha</code> property. */
+ private static final IntProperty<Drawable> DRAWABLE_ALPHA =
+ new IntProperty<Drawable>("alpha") {
+ @Override
+ public void setValue(Drawable object, int value) {
+ object.setAlpha(value);
+ }
+
+ @Override
+ public Integer get(Drawable object) {
+ return object.getAlpha();
+ }
+ };
+
+ /*
+ * WARNING: This is a workaround for a touch mode issue.
+ *
+ * Touch mode is propagated lazily to windows. This causes problems in
+ * the following scenario:
+ * - Type something in the AutoCompleteTextView and get some results
+ * - Move down with the d-pad to select an item in the list
+ * - Move up with the d-pad until the selection disappears
+ * - Type more text in the AutoCompleteTextView *using the soft keyboard*
+ * and get new results; you are now in touch mode
+ * - The selection comes back on the first item in the list, even though
+ * the list is supposed to be in touch mode
+ *
+ * Using the soft keyboard triggers the touch mode change but that change
+ * is propagated to our window only after the first list layout, therefore
+ * after the list attempts to resurrect the selection.
+ *
+ * The trick to work around this issue is to pretend the list is in touch
+ * mode when we know that the selection should not appear, that is when
+ * we know the user moved the selection away from the list.
+ *
+ * This boolean is set to true whenever we explicitly hide the list's
+ * selection and reset to false whenever we know the user moved the
+ * selection back to the list.
+ *
+ * When this boolean is true, isInTouchMode() returns true, otherwise it
+ * returns super.isInTouchMode().
+ */
+ private boolean mListSelectionHidden;
+
+ /**
+ * True if this wrapper should fake focus.
+ */
+ private boolean mHijackFocus;
+
+ /** Whether to force drawing of the pressed state selector. */
+ private boolean mDrawsInPressedState;
+
+ /** Current drag-to-open click animation, if any. */
+ private Animator mClickAnimation;
+
+ /** Helper for drag-to-open auto scrolling. */
+ private AbsListViewAutoScroller mScrollHelper;
+
+ /**
+ * Creates a new list view wrapper.
+ *
+ * @param context this view's context
+ */
+ public DropDownListView(Context context, boolean hijackFocus) {
+ this(context, hijackFocus, com.android.internal.R.attr.dropDownListViewStyle);
+ }
+
+ /**
+ * Creates a new list view wrapper.
+ *
+ * @param context this view's context
+ */
+ public DropDownListView(Context context, boolean hijackFocus, int defStyleAttr) {
+ super(context, null, defStyleAttr);
+ mHijackFocus = hijackFocus;
+ // TODO: Add an API to control this
+ setCacheColorHint(0); // Transparent, since the background drawable could be anything.
+ }
+
+ /**
+ * Handles forwarded events.
+ *
+ * @param activePointerId id of the pointer that activated forwarding
+ * @return whether the event was handled
+ */
+ public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
+ boolean handledEvent = true;
+ boolean clearPressedItem = false;
+
+ final int actionMasked = event.getActionMasked();
+ switch (actionMasked) {
+ case MotionEvent.ACTION_CANCEL:
+ handledEvent = false;
+ break;
+ case MotionEvent.ACTION_UP:
+ handledEvent = false;
+ // $FALL-THROUGH$
+ case MotionEvent.ACTION_MOVE:
+ final int activeIndex = event.findPointerIndex(activePointerId);
+ if (activeIndex < 0) {
+ handledEvent = false;
+ break;
+ }
+
+ final int x = (int) event.getX(activeIndex);
+ final int y = (int) event.getY(activeIndex);
+ final int position = pointToPosition(x, y);
+ if (position == INVALID_POSITION) {
+ clearPressedItem = true;
+ break;
+ }
+
+ final View child = getChildAt(position - getFirstVisiblePosition());
+ setPressedItem(child, position, x, y);
+ handledEvent = true;
+
+ if (actionMasked == MotionEvent.ACTION_UP) {
+ clickPressedItem(child, position);
+ }
+ break;
+ }
+
+ // Failure to handle the event cancels forwarding.
+ if (!handledEvent || clearPressedItem) {
+ clearPressedItem();
+ }
+
+ // Manage automatic scrolling.
+ if (handledEvent) {
+ if (mScrollHelper == null) {
+ mScrollHelper = new AbsListViewAutoScroller(this);
+ }
+ mScrollHelper.setEnabled(true);
+ mScrollHelper.onTouch(this, event);
+ } else if (mScrollHelper != null) {
+ mScrollHelper.setEnabled(false);
+ }
+
+ return handledEvent;
+ }
+
+ /**
+ * Sets whether the list selection is hidden, as part of a workaround for a touch mode issue
+ * (see the declaration for mListSelectionHidden).
+ * @param listSelectionHidden
+ */
+ public void setListSelectionHidden(boolean listSelectionHidden) {
+ this.mListSelectionHidden = listSelectionHidden;
+ }
+
+ /**
+ * Starts an alpha animation on the selector. When the animation ends,
+ * the list performs a click on the item.
+ */
+ private void clickPressedItem(final View child, final int position) {
+ final long id = getItemIdAtPosition(position);
+ final Animator anim = ObjectAnimator.ofInt(
+ mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
+ anim.setDuration(CLICK_ANIM_DURATION);
+ anim.setInterpolator(new AccelerateDecelerateInterpolator());
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ performItemClick(child, position, id);
+ }
+ });
+ anim.start();
+
+ if (mClickAnimation != null) {
+ mClickAnimation.cancel();
+ }
+ mClickAnimation = anim;
+ }
+
+ private void clearPressedItem() {
+ mDrawsInPressedState = false;
+ setPressed(false);
+ updateSelectorState();
+
+ final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+ if (motionView != null) {
+ motionView.setPressed(false);
+ }
+
+ if (mClickAnimation != null) {
+ mClickAnimation.cancel();
+ mClickAnimation = null;
+ }
+ }
+
+ private void setPressedItem(View child, int position, float x, float y) {
+ mDrawsInPressedState = true;
+
+ // Ordering is essential. First, update the container's pressed state.
+ drawableHotspotChanged(x, y);
+ if (!isPressed()) {
+ setPressed(true);
+ }
+
+ // Next, run layout if we need to stabilize child positions.
+ if (mDataChanged) {
+ layoutChildren();
+ }
+
+ // Manage the pressed view based on motion position. This allows us to
+ // play nicely with actual touch and scroll events.
+ final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+ if (motionView != null && motionView != child && motionView.isPressed()) {
+ motionView.setPressed(false);
+ }
+ mMotionPosition = position;
+
+ // Offset for child coordinates.
+ final float childX = x - child.getLeft();
+ final float childY = y - child.getTop();
+ child.drawableHotspotChanged(childX, childY);
+ if (!child.isPressed()) {
+ child.setPressed(true);
+ }
+
+ // Ensure that keyboard focus starts from the last touched position.
+ setSelectedPositionInt(position);
+ positionSelectorLikeTouch(position, child, x, y);
+
+ // Refresh the drawable state to reflect the new pressed state,
+ // which will also update the selector state.
+ refreshDrawableState();
+
+ if (mClickAnimation != null) {
+ mClickAnimation.cancel();
+ mClickAnimation = null;
+ }
+ }
+
+ @Override
+ boolean touchModeDrawsInPressedState() {
+ return mDrawsInPressedState || super.touchModeDrawsInPressedState();
+ }
+
+ /**
+ * Avoids jarring scrolling effect by ensuring that list elements
+ * made of a text view fit on a single line.
+ *
+ * @param position the item index in the list to get a view for
+ * @return the view for the specified item
+ */
+ @Override
+ View obtainView(int position, boolean[] isScrap) {
+ View view = super.obtainView(position, isScrap);
+
+ if (view instanceof TextView) {
+ ((TextView) view).setHorizontallyScrolling(true);
+ }
+
+ return view;
+ }
+
+ @Override
+ public boolean isInTouchMode() {
+ // WARNING: Please read the comment where mListSelectionHidden is declared
+ return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
+ }
+
+ /**
+ * Returns the focus state in the drop down.
+ *
+ * @return true always if hijacking focus
+ */
+ @Override
+ public boolean hasWindowFocus() {
+ return mHijackFocus || super.hasWindowFocus();
+ }
+
+ /**
+ * Returns the focus state in the drop down.
+ *
+ * @return true always if hijacking focus
+ */
+ @Override
+ public boolean isFocused() {
+ return mHijackFocus || super.isFocused();
+ }
+
+ /**
+ * Returns the focus state in the drop down.
+ *
+ * @return true always if hijacking focus
+ */
+ @Override
+ public boolean hasFocus() {
+ return mHijackFocus || super.hasFocus();
+ }
+} \ No newline at end of file
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
new file mode 100644
index 000000000000..fd7140f779fe
--- /dev/null
+++ b/core/java/android/widget/ForwardingListener.java
@@ -0,0 +1,299 @@
+/*
+ * 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.widget;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
+
+import com.android.internal.view.menu.ShowableListMenu;
+
+/**
+ * Abstract class that forwards touch events to a {@link ListPopupWindow}.
+ *
+ * @hide
+ */
+public abstract class ForwardingListener
+ implements View.OnTouchListener, View.OnAttachStateChangeListener {
+
+ /** Scaled touch slop, used for detecting movement outside bounds. */
+ private final float mScaledTouchSlop;
+
+ /** Timeout before disallowing intercept on the source's parent. */
+ private final int mTapTimeout;
+
+ /** Timeout before accepting a long-press to start forwarding. */
+ private final int mLongPressTimeout;
+
+ /** Source view from which events are forwarded. */
+ private final View mSrc;
+
+ /** Runnable used to prevent conflicts with scrolling parents. */
+ private Runnable mDisallowIntercept;
+
+ /** Runnable used to trigger forwarding on long-press. */
+ private Runnable mTriggerLongPress;
+
+ /** Whether this listener is currently forwarding touch events. */
+ private boolean mForwarding;
+
+ /**
+ * Whether forwarding was initiated by a long-press. If so, we won't
+ * force the window to dismiss when the touch stream ends.
+ */
+ private boolean mWasLongPress;
+
+ /** The id of the first pointer down in the current event stream. */
+ private int mActivePointerId;
+
+ public ForwardingListener(View src) {
+ mSrc = src;
+ mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
+ mTapTimeout = ViewConfiguration.getTapTimeout();
+
+ // Use a medium-press timeout. Halfway between tap and long-press.
+ mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
+
+ src.addOnAttachStateChangeListener(this);
+ }
+
+ /**
+ * Returns the popup to which this listener is forwarding events.
+ * <p>
+ * Override this to return the correct popup. If the popup is displayed
+ * asynchronously, you may also need to override
+ * {@link #onForwardingStopped} to prevent premature cancellation of
+ * forwarding.
+ *
+ * @return the popup to which this listener is forwarding events
+ */
+ public abstract ShowableListMenu getPopup();
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ final boolean wasForwarding = mForwarding;
+ final boolean forwarding;
+ if (wasForwarding) {
+ forwarding = onTouchForwarded(event) || !onForwardingStopped();
+ } else {
+ forwarding = onTouchObserved(event) && onForwardingStarted();
+
+ if (forwarding) {
+ // Make sure we cancel any ongoing source event stream.
+ final long now = SystemClock.uptimeMillis();
+ final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
+ 0.0f, 0.0f, 0);
+ mSrc.onTouchEvent(e);
+ e.recycle();
+ }
+ }
+
+ mForwarding = forwarding;
+ return forwarding || wasForwarding;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ mForwarding = false;
+ mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+ if (mDisallowIntercept != null) {
+ mSrc.removeCallbacks(mDisallowIntercept);
+ }
+ }
+
+ /**
+ * Called when forwarding would like to start.
+ * <p>
+ * By default, this will show the popup returned by {@link #getPopup()}.
+ * It may be overridden to perform another action, like clicking the
+ * source view or preparing the popup before showing it.
+ *
+ * @return true to start forwarding, false otherwise
+ */
+ protected boolean onForwardingStarted() {
+ final ShowableListMenu popup = getPopup();
+ if (popup != null && !popup.isShowing()) {
+ popup.show();
+ }
+ return true;
+ }
+
+ /**
+ * Called when forwarding would like to stop.
+ * <p>
+ * By default, this will dismiss the popup returned by
+ * {@link #getPopup()}. It may be overridden to perform some other
+ * action.
+ *
+ * @return true to stop forwarding, false otherwise
+ */
+ protected boolean onForwardingStopped() {
+ final ShowableListMenu popup = getPopup();
+ if (popup != null && popup.isShowing()) {
+ popup.dismiss();
+ }
+ return true;
+ }
+
+ /**
+ * Observes motion events and determines when to start forwarding.
+ *
+ * @param srcEvent motion event in source view coordinates
+ * @return true to start forwarding motion events, false otherwise
+ */
+ private boolean onTouchObserved(MotionEvent srcEvent) {
+ final View src = mSrc;
+ if (!src.isEnabled()) {
+ return false;
+ }
+
+ final int actionMasked = srcEvent.getActionMasked();
+ switch (actionMasked) {
+ case MotionEvent.ACTION_DOWN:
+ mActivePointerId = srcEvent.getPointerId(0);
+ mWasLongPress = false;
+
+ if (mDisallowIntercept == null) {
+ mDisallowIntercept = new DisallowIntercept();
+ }
+ src.postDelayed(mDisallowIntercept, mTapTimeout);
+
+ if (mTriggerLongPress == null) {
+ mTriggerLongPress = new TriggerLongPress();
+ }
+ src.postDelayed(mTriggerLongPress, mLongPressTimeout);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
+ if (activePointerIndex >= 0) {
+ final float x = srcEvent.getX(activePointerIndex);
+ final float y = srcEvent.getY(activePointerIndex);
+
+ // Has the pointer moved outside of the view?
+ if (!src.pointInView(x, y, mScaledTouchSlop)) {
+ clearCallbacks();
+
+ // Don't let the parent intercept our events.
+ src.getParent().requestDisallowInterceptTouchEvent(true);
+ return true;
+ }
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ clearCallbacks();
+ break;
+ }
+
+ return false;
+ }
+
+ private void clearCallbacks() {
+ if (mTriggerLongPress != null) {
+ mSrc.removeCallbacks(mTriggerLongPress);
+ }
+
+ if (mDisallowIntercept != null) {
+ mSrc.removeCallbacks(mDisallowIntercept);
+ }
+ }
+
+ private void onLongPress() {
+ clearCallbacks();
+
+ final View src = mSrc;
+ if (!src.isEnabled() || src.isLongClickable()) {
+ // Ignore long-press if the view is disabled or has its own
+ // handler.
+ return;
+ }
+
+ if (!onForwardingStarted()) {
+ return;
+ }
+
+ // Don't let the parent intercept our events.
+ src.getParent().requestDisallowInterceptTouchEvent(true);
+
+ // Make sure we cancel any ongoing source event stream.
+ final long now = SystemClock.uptimeMillis();
+ final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+ src.onTouchEvent(e);
+ e.recycle();
+
+ mForwarding = true;
+ mWasLongPress = true;
+ }
+
+ /**
+ * Handles forwarded motion events and determines when to stop
+ * forwarding.
+ *
+ * @param srcEvent motion event in source view coordinates
+ * @return true to continue forwarding motion events, false to cancel
+ */
+ private boolean onTouchForwarded(MotionEvent srcEvent) {
+ final View src = mSrc;
+ final ShowableListMenu popup = getPopup();
+ if (popup == null || !popup.isShowing()) {
+ return false;
+ }
+
+ final DropDownListView dst = (DropDownListView) popup.getListView();
+ if (dst == null || !dst.isShown()) {
+ return false;
+ }
+
+ // Convert event to destination-local coordinates.
+ final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
+ src.toGlobalMotionEvent(dstEvent);
+ dst.toLocalMotionEvent(dstEvent);
+
+ // Forward converted event to destination view, then recycle it.
+ final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId);
+ dstEvent.recycle();
+
+ // Always cancel forwarding when the touch stream ends.
+ final int action = srcEvent.getActionMasked();
+ final boolean keepForwarding = action != MotionEvent.ACTION_UP
+ && action != MotionEvent.ACTION_CANCEL;
+
+ return handled && keepForwarding;
+ }
+
+ private class DisallowIntercept implements Runnable {
+ @Override
+ public void run() {
+ final ViewParent parent = mSrc.getParent();
+ parent.requestDisallowInterceptTouchEvent(true);
+ }
+ }
+
+ private class TriggerLongPress implements Runnable {
+ @Override
+ public void run() {
+ onLongPress();
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index a02efcff4197..3d07d87dfe70 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -25,7 +25,6 @@ import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.os.SystemClock;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.IntProperty;
@@ -36,13 +35,13 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
import java.util.Locale;
@@ -58,7 +57,7 @@ import java.util.Locale;
* @see android.widget.AutoCompleteTextView
* @see android.widget.Spinner
*/
-public class ListPopupWindow {
+public class ListPopupWindow implements ShowableListMenu {
private static final String TAG = "ListPopupWindow";
private static final boolean DEBUG = false;
@@ -580,6 +579,7 @@ public class ListPopupWindow {
* Show the popup list. If the list is already showing, this method
* will recalculate the popup's size and position.
*/
+ @Override
public void show() {
int height = buildDropDown();
@@ -671,6 +671,7 @@ public class ListPopupWindow {
/**
* Dismiss the popup window.
*/
+ @Override
public void dismiss() {
mPopup.dismiss();
removePromptView();
@@ -732,7 +733,7 @@ public class ListPopupWindow {
public void setSelection(int position) {
DropDownListView list = mDropDownList;
if (isShowing() && list != null) {
- list.mListSelectionHidden = false;
+ list.setListSelectionHidden(false);
list.setSelection(position);
if (list.getChoiceMode() != ListView.CHOICE_MODE_NONE) {
list.setItemChecked(position, true);
@@ -748,7 +749,7 @@ public class ListPopupWindow {
final DropDownListView list = mDropDownList;
if (list != null) {
// WARNING: Please read the comment where mListSelectionHidden is declared
- list.mListSelectionHidden = true;
+ list.setListSelectionHidden(true);
list.hideSelector();
list.requestLayout();
}
@@ -757,6 +758,7 @@ public class ListPopupWindow {
/**
* @return {@code true} if the popup is currently showing, {@code false} otherwise.
*/
+ @Override
public boolean isShowing() {
return mPopup.isShowing();
}
@@ -842,6 +844,7 @@ public class ListPopupWindow {
* @return The {@link ListView} displayed within the popup window.
* Only valid when {@link #isShowing()} == {@code true}.
*/
+ @Override
public ListView getListView() {
return mDropDownList;
}
@@ -911,7 +914,7 @@ public class ListPopupWindow {
} else {
// WARNING: Please read the comment where mListSelectionHidden
// is declared
- mDropDownList.mListSelectionHidden = false;
+ mDropDownList.setListSelectionHidden(false);
}
consumed = mDropDownList.onKeyDown(keyCode, event);
@@ -1037,7 +1040,7 @@ public class ListPopupWindow {
public OnTouchListener createDragToOpenListener(View src) {
return new ForwardingListener(src) {
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
return ListPopupWindow.this;
}
};
@@ -1088,7 +1091,7 @@ public class ListPopupWindow {
DropDownListView dropDownList = mDropDownList;
if (dropDownList != null) {
- dropDownList.mListSelectionHidden = false;
+ dropDownList.setListSelectionHidden(false);
}
}
}
@@ -1219,568 +1222,6 @@ public class ListPopupWindow {
return listContent + otherHeights;
}
- /**
- * Abstract class that forwards touch events to a {@link ListPopupWindow}.
- *
- * @hide
- */
- public static abstract class ForwardingListener
- implements View.OnTouchListener, View.OnAttachStateChangeListener {
- /** Scaled touch slop, used for detecting movement outside bounds. */
- private final float mScaledTouchSlop;
-
- /** Timeout before disallowing intercept on the source's parent. */
- private final int mTapTimeout;
-
- /** Timeout before accepting a long-press to start forwarding. */
- private final int mLongPressTimeout;
-
- /** Source view from which events are forwarded. */
- private final View mSrc;
-
- /** Runnable used to prevent conflicts with scrolling parents. */
- private Runnable mDisallowIntercept;
-
- /** Runnable used to trigger forwarding on long-press. */
- private Runnable mTriggerLongPress;
-
- /** Whether this listener is currently forwarding touch events. */
- private boolean mForwarding;
-
- /**
- * Whether forwarding was initiated by a long-press. If so, we won't
- * force the window to dismiss when the touch stream ends.
- */
- private boolean mWasLongPress;
-
- /** The id of the first pointer down in the current event stream. */
- private int mActivePointerId;
-
- public ForwardingListener(View src) {
- mSrc = src;
- mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
- mTapTimeout = ViewConfiguration.getTapTimeout();
-
- // Use a medium-press timeout. Halfway between tap and long-press.
- mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
-
- src.addOnAttachStateChangeListener(this);
- }
-
- /**
- * Returns the popup to which this listener is forwarding events.
- * <p>
- * Override this to return the correct popup. If the popup is displayed
- * asynchronously, you may also need to override
- * {@link #onForwardingStopped} to prevent premature cancelation of
- * forwarding.
- *
- * @return the popup to which this listener is forwarding events
- */
- public abstract ListPopupWindow getPopup();
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- final boolean wasForwarding = mForwarding;
- final boolean forwarding;
- if (wasForwarding) {
- forwarding = onTouchForwarded(event) || !onForwardingStopped();
- } else {
- forwarding = onTouchObserved(event) && onForwardingStarted();
-
- if (forwarding) {
- // Make sure we cancel any ongoing source event stream.
- final long now = SystemClock.uptimeMillis();
- final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
- 0.0f, 0.0f, 0);
- mSrc.onTouchEvent(e);
- e.recycle();
- }
- }
-
- mForwarding = forwarding;
- return forwarding || wasForwarding;
- }
-
- @Override
- public void onViewAttachedToWindow(View v) {
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- mForwarding = false;
- mActivePointerId = MotionEvent.INVALID_POINTER_ID;
-
- if (mDisallowIntercept != null) {
- mSrc.removeCallbacks(mDisallowIntercept);
- }
- }
-
- /**
- * Called when forwarding would like to start.
- * <p>
- * By default, this will show the popup returned by {@link #getPopup()}.
- * It may be overridden to perform another action, like clicking the
- * source view or preparing the popup before showing it.
- *
- * @return true to start forwarding, false otherwise
- */
- protected boolean onForwardingStarted() {
- final ListPopupWindow popup = getPopup();
- if (popup != null && !popup.isShowing()) {
- popup.show();
- }
- return true;
- }
-
- /**
- * Called when forwarding would like to stop.
- * <p>
- * By default, this will dismiss the popup returned by
- * {@link #getPopup()}. It may be overridden to perform some other
- * action.
- *
- * @return true to stop forwarding, false otherwise
- */
- protected boolean onForwardingStopped() {
- final ListPopupWindow popup = getPopup();
- if (popup != null && popup.isShowing()) {
- popup.dismiss();
- }
- return true;
- }
-
- /**
- * Observes motion events and determines when to start forwarding.
- *
- * @param srcEvent motion event in source view coordinates
- * @return true to start forwarding motion events, false otherwise
- */
- private boolean onTouchObserved(MotionEvent srcEvent) {
- final View src = mSrc;
- if (!src.isEnabled()) {
- return false;
- }
-
- final int actionMasked = srcEvent.getActionMasked();
- switch (actionMasked) {
- case MotionEvent.ACTION_DOWN:
- mActivePointerId = srcEvent.getPointerId(0);
- mWasLongPress = false;
-
- if (mDisallowIntercept == null) {
- mDisallowIntercept = new DisallowIntercept();
- }
- src.postDelayed(mDisallowIntercept, mTapTimeout);
-
- if (mTriggerLongPress == null) {
- mTriggerLongPress = new TriggerLongPress();
- }
- src.postDelayed(mTriggerLongPress, mLongPressTimeout);
- break;
- case MotionEvent.ACTION_MOVE:
- final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
- if (activePointerIndex >= 0) {
- final float x = srcEvent.getX(activePointerIndex);
- final float y = srcEvent.getY(activePointerIndex);
-
- // Has the pointer has moved outside of the view?
- if (!src.pointInView(x, y, mScaledTouchSlop)) {
- clearCallbacks();
-
- // Don't let the parent intercept our events.
- src.getParent().requestDisallowInterceptTouchEvent(true);
- return true;
- }
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- clearCallbacks();
- break;
- }
-
- return false;
- }
-
- private void clearCallbacks() {
- if (mTriggerLongPress != null) {
- mSrc.removeCallbacks(mTriggerLongPress);
- }
-
- if (mDisallowIntercept != null) {
- mSrc.removeCallbacks(mDisallowIntercept);
- }
- }
-
- private void onLongPress() {
- clearCallbacks();
-
- final View src = mSrc;
- if (!src.isEnabled() || src.isLongClickable()) {
- // Ignore long-press if the view is disabled or has its own
- // handler.
- return;
- }
-
- if (!onForwardingStarted()) {
- return;
- }
-
- // Don't let the parent intercept our events.
- src.getParent().requestDisallowInterceptTouchEvent(true);
-
- // Make sure we cancel any ongoing source event stream.
- final long now = SystemClock.uptimeMillis();
- final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
- src.onTouchEvent(e);
- e.recycle();
-
- mForwarding = true;
- mWasLongPress = true;
- }
-
- /**
- * Handled forwarded motion events and determines when to stop
- * forwarding.
- *
- * @param srcEvent motion event in source view coordinates
- * @return true to continue forwarding motion events, false to cancel
- */
- private boolean onTouchForwarded(MotionEvent srcEvent) {
- final View src = mSrc;
- final ListPopupWindow popup = getPopup();
- if (popup == null || !popup.isShowing()) {
- return false;
- }
-
- final DropDownListView dst = popup.mDropDownList;
- if (dst == null || !dst.isShown()) {
- return false;
- }
-
- // Convert event to destination-local coordinates.
- final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
- src.toGlobalMotionEvent(dstEvent);
- dst.toLocalMotionEvent(dstEvent);
-
- // Forward converted event to destination view, then recycle it.
- final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId);
- dstEvent.recycle();
-
- // Always cancel forwarding when the touch stream ends.
- final int action = srcEvent.getActionMasked();
- final boolean keepForwarding = action != MotionEvent.ACTION_UP
- && action != MotionEvent.ACTION_CANCEL;
-
- return handled && keepForwarding;
- }
-
- private class DisallowIntercept implements Runnable {
- @Override
- public void run() {
- final ViewParent parent = mSrc.getParent();
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
-
- private class TriggerLongPress implements Runnable {
- @Override
- public void run() {
- onLongPress();
- }
- }
- }
-
- /**
- * <p>Wrapper class for a ListView. This wrapper can hijack the focus to
- * make sure the list uses the appropriate drawables and states when
- * displayed on screen within a drop down. The focus is never actually
- * passed to the drop down in this mode; the list only looks focused.</p>
- */
- static class DropDownListView extends ListView {
- /** Duration in milliseconds of the drag-to-open click animation. */
- private static final long CLICK_ANIM_DURATION = 150;
-
- /** Target alpha value for drag-to-open click animation. */
- private static final int CLICK_ANIM_ALPHA = 0x80;
-
- /** Wrapper around Drawable's <code>alpha</code> property. */
- private static final IntProperty<Drawable> DRAWABLE_ALPHA =
- new IntProperty<Drawable>("alpha") {
- @Override
- public void setValue(Drawable object, int value) {
- object.setAlpha(value);
- }
-
- @Override
- public Integer get(Drawable object) {
- return object.getAlpha();
- }
- };
-
- /*
- * WARNING: This is a workaround for a touch mode issue.
- *
- * Touch mode is propagated lazily to windows. This causes problems in
- * the following scenario:
- * - Type something in the AutoCompleteTextView and get some results
- * - Move down with the d-pad to select an item in the list
- * - Move up with the d-pad until the selection disappears
- * - Type more text in the AutoCompleteTextView *using the soft keyboard*
- * and get new results; you are now in touch mode
- * - The selection comes back on the first item in the list, even though
- * the list is supposed to be in touch mode
- *
- * Using the soft keyboard triggers the touch mode change but that change
- * is propagated to our window only after the first list layout, therefore
- * after the list attempts to resurrect the selection.
- *
- * The trick to work around this issue is to pretend the list is in touch
- * mode when we know that the selection should not appear, that is when
- * we know the user moved the selection away from the list.
- *
- * This boolean is set to true whenever we explicitly hide the list's
- * selection and reset to false whenever we know the user moved the
- * selection back to the list.
- *
- * When this boolean is true, isInTouchMode() returns true, otherwise it
- * returns super.isInTouchMode().
- */
- private boolean mListSelectionHidden;
-
- /**
- * True if this wrapper should fake focus.
- */
- private boolean mHijackFocus;
-
- /** Whether to force drawing of the pressed state selector. */
- private boolean mDrawsInPressedState;
-
- /** Current drag-to-open click animation, if any. */
- private Animator mClickAnimation;
-
- /** Helper for drag-to-open auto scrolling. */
- private AbsListViewAutoScroller mScrollHelper;
-
- /**
- * <p>Creates a new list view wrapper.</p>
- *
- * @param context this view's context
- */
- public DropDownListView(Context context, boolean hijackFocus) {
- super(context, null, com.android.internal.R.attr.dropDownListViewStyle);
- mHijackFocus = hijackFocus;
- // TODO: Add an API to control this
- setCacheColorHint(0); // Transparent, since the background drawable could be anything.
- }
-
- /**
- * Handles forwarded events.
- *
- * @param activePointerId id of the pointer that activated forwarding
- * @return whether the event was handled
- */
- public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
- boolean handledEvent = true;
- boolean clearPressedItem = false;
-
- final int actionMasked = event.getActionMasked();
- switch (actionMasked) {
- case MotionEvent.ACTION_CANCEL:
- handledEvent = false;
- break;
- case MotionEvent.ACTION_UP:
- handledEvent = false;
- // $FALL-THROUGH$
- case MotionEvent.ACTION_MOVE:
- final int activeIndex = event.findPointerIndex(activePointerId);
- if (activeIndex < 0) {
- handledEvent = false;
- break;
- }
-
- final int x = (int) event.getX(activeIndex);
- final int y = (int) event.getY(activeIndex);
- final int position = pointToPosition(x, y);
- if (position == INVALID_POSITION) {
- clearPressedItem = true;
- break;
- }
-
- final View child = getChildAt(position - getFirstVisiblePosition());
- setPressedItem(child, position, x, y);
- handledEvent = true;
-
- if (actionMasked == MotionEvent.ACTION_UP) {
- clickPressedItem(child, position);
- }
- break;
- }
-
- // Failure to handle the event cancels forwarding.
- if (!handledEvent || clearPressedItem) {
- clearPressedItem();
- }
-
- // Manage automatic scrolling.
- if (handledEvent) {
- if (mScrollHelper == null) {
- mScrollHelper = new AbsListViewAutoScroller(this);
- }
- mScrollHelper.setEnabled(true);
- mScrollHelper.onTouch(this, event);
- } else if (mScrollHelper != null) {
- mScrollHelper.setEnabled(false);
- }
-
- return handledEvent;
- }
-
- /**
- * Starts an alpha animation on the selector. When the animation ends,
- * the list performs a click on the item.
- */
- private void clickPressedItem(final View child, final int position) {
- final long id = getItemIdAtPosition(position);
- final Animator anim = ObjectAnimator.ofInt(
- mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
- anim.setDuration(CLICK_ANIM_DURATION);
- anim.setInterpolator(new AccelerateDecelerateInterpolator());
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- performItemClick(child, position, id);
- }
- });
- anim.start();
-
- if (mClickAnimation != null) {
- mClickAnimation.cancel();
- }
- mClickAnimation = anim;
- }
-
- private void clearPressedItem() {
- mDrawsInPressedState = false;
- setPressed(false);
- updateSelectorState();
-
- final View motionView = getChildAt(mMotionPosition - mFirstPosition);
- if (motionView != null) {
- motionView.setPressed(false);
- }
-
- if (mClickAnimation != null) {
- mClickAnimation.cancel();
- mClickAnimation = null;
- }
- }
-
- private void setPressedItem(View child, int position, float x, float y) {
- mDrawsInPressedState = true;
-
- // Ordering is essential. First, update the container's pressed state.
- drawableHotspotChanged(x, y);
- if (!isPressed()) {
- setPressed(true);
- }
-
- // Next, run layout if we need to stabilize child positions.
- if (mDataChanged) {
- layoutChildren();
- }
-
- // Manage the pressed view based on motion position. This allows us to
- // play nicely with actual touch and scroll events.
- final View motionView = getChildAt(mMotionPosition - mFirstPosition);
- if (motionView != null && motionView != child && motionView.isPressed()) {
- motionView.setPressed(false);
- }
- mMotionPosition = position;
-
- // Offset for child coordinates.
- final float childX = x - child.getLeft();
- final float childY = y - child.getTop();
- child.drawableHotspotChanged(childX, childY);
- if (!child.isPressed()) {
- child.setPressed(true);
- }
-
- // Ensure that keyboard focus starts from the last touched position.
- setSelectedPositionInt(position);
- positionSelectorLikeTouch(position, child, x, y);
-
- // Refresh the drawable state to reflect the new pressed state,
- // which will also update the selector state.
- refreshDrawableState();
-
- if (mClickAnimation != null) {
- mClickAnimation.cancel();
- mClickAnimation = null;
- }
- }
-
- @Override
- boolean touchModeDrawsInPressedState() {
- return mDrawsInPressedState || super.touchModeDrawsInPressedState();
- }
-
- /**
- * <p>Avoids jarring scrolling effect by ensuring that list elements
- * made of a text view fit on a single line.</p>
- *
- * @param position the item index in the list to get a view for
- * @return the view for the specified item
- */
- @Override
- View obtainView(int position, boolean[] isScrap) {
- View view = super.obtainView(position, isScrap);
-
- if (view instanceof TextView) {
- ((TextView) view).setHorizontallyScrolling(true);
- }
-
- return view;
- }
-
- @Override
- public boolean isInTouchMode() {
- // WARNING: Please read the comment where mListSelectionHidden is declared
- return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
- }
-
- /**
- * <p>Returns the focus state in the drop down.</p>
- *
- * @return true always if hijacking focus
- */
- @Override
- public boolean hasWindowFocus() {
- return mHijackFocus || super.hasWindowFocus();
- }
-
- /**
- * <p>Returns the focus state in the drop down.</p>
- *
- * @return true always if hijacking focus
- */
- @Override
- public boolean isFocused() {
- return mHijackFocus || super.isFocused();
- }
-
- /**
- * <p>Returns the focus state in the drop down.</p>
- *
- * @return true always if hijacking focus
- */
- @Override
- public boolean hasFocus() {
- return mHijackFocus || super.hasFocus();
- }
- }
-
private class PopupDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index 8d42c739b627..9e47e8513d49 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -36,11 +36,11 @@ public class MenuPopupWindow extends ListPopupWindow {
}
@Override
- ListPopupWindow.DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
+ DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
return new MenuDropDownListView(context, hijackFocus);
}
- static class MenuDropDownListView extends ListPopupWindow.DropDownListView {
+ static class MenuDropDownListView extends DropDownListView {
private boolean mHoveredOnDisabledItem = false;
private AccessibilityManager mAccessibilityManager;
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 1507dfb29285..3b2d60d1e1a4 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -20,6 +20,7 @@ import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.ShowableListMenu;
import com.android.internal.view.menu.SubMenuBuilder;
import android.annotation.MenuRes;
@@ -30,7 +31,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnTouchListener;
-import android.widget.ListPopupWindow.ForwardingListener;
/**
* A PopupMenu displays a {@link Menu} in a modal popup window anchored to a {@link View}.
@@ -170,7 +170,7 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
}
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
// This will be null until show() is called.
return mPopup.getPopup();
}
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index f3cf61c7a1eb..c79e18449e39 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -17,6 +17,7 @@
package android.widget;
import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
import android.annotation.DrawableRes;
import android.annotation.Nullable;
@@ -44,7 +45,6 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.ListPopupWindow.ForwardingListener;
import android.widget.PopupWindow.OnDismissListener;
/**
@@ -278,7 +278,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
mPopup = popup;
mForwardingListener = new ForwardingListener(this) {
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
return popup;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7a6437724e2f..61402abcece7 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -21,6 +21,7 @@ import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Size;
import android.annotation.StringRes;
import android.annotation.StyleRes;
import android.annotation.XmlRes;
@@ -103,6 +104,7 @@ import android.text.style.URLSpan;
import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
import android.util.AttributeSet;
+import android.util.LocaleList;
import android.util.Log;
import android.util.TypedValue;
import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -553,7 +555,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private final TextPaint mTextPaint;
private boolean mUserSetTextScaleX;
private Layout mLayout;
- private boolean mLocaleChanged = false;
+ private boolean mLocalesChanged = false;
@ViewDebug.ExportedProperty(category = "text")
private int mGravity = Gravity.TOP | Gravity.START;
@@ -2817,32 +2819,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Get the default {@link Locale} of the text in this TextView.
- * @return the default {@link Locale} of the text in this TextView.
+ * Get the default primary {@link Locale} of the text in this TextView. This will always be
+ * the first member of {@link #getTextLocales()}.
+ * @return the default primary {@link Locale} of the text in this TextView.
*/
+ @NonNull
public Locale getTextLocale() {
return mTextPaint.getTextLocale();
}
/**
- * Set the default {@link Locale} of the text in this TextView to the given value. This value
- * is used to choose appropriate typefaces for ambiguous characters. Typically used for CJK
- * locales to disambiguate Hanzi/Kanji/Hanja characters.
+ * Get the default {@link LocaleList} of the text in this TextView.
+ * @return the default {@link LocaleList} of the text in this TextView.
+ */
+ @NonNull @Size(min=1)
+ public LocaleList getTextLocales() {
+ return mTextPaint.getTextLocales();
+ }
+
+ /**
+ * Set the default {@link LocaleList} of the text in this TextView to a one-member list
+ * containing just the given value.
*
* @param locale the {@link Locale} for drawing text, must not be null.
*
- * @see Paint#setTextLocale
+ * @see #setTextLocales
*/
- public void setTextLocale(Locale locale) {
- mLocaleChanged = true;
+ public void setTextLocale(@NonNull Locale locale) {
+ mLocalesChanged = true;
mTextPaint.setTextLocale(locale);
}
+ /**
+ * Set the default {@link LocaleList} of the text in this TextView to the given value.
+ *
+ * This value is used to choose appropriate typefaces for ambiguous characters (typically used
+ * for CJK locales to disambiguate Hanzi/Kanji/Hanja characters). It also affects
+ * other aspects of text display, including line breaking.
+ *
+ * @param locales the {@link LocaleList} for drawing text, must not be null or empty.
+ *
+ * @see Paint#setTextLocales
+ */
+ public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+ mLocalesChanged = true;
+ mTextPaint.setTextLocales(locales);
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- if (!mLocaleChanged) {
- mTextPaint.setTextLocale(Locale.getDefault());
+ if (!mLocalesChanged) {
+ mTextPaint.setTextLocales(LocaleList.getDefault());
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8cf7ece..4f4d3e0faa44 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -338,7 +338,7 @@ public final class BatteryStatsHelper {
}
if (mCpuPowerCalculator == null) {
- mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+ mCpuPowerCalculator = new CpuPowerCalculator();
}
mCpuPowerCalculator.reset();
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index a3ef612077bf..d62f7a689157 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -23,54 +23,14 @@ public class CpuPowerCalculator extends PowerCalculator {
private static final String TAG = "CpuPowerCalculator";
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
- private final double[] mPowerCpuNormal;
-
- /**
- * Reusable array for calculations.
- */
- private final long[] mSpeedStepTimes;
-
- public CpuPowerCalculator(PowerProfile profile) {
- final int speedSteps = profile.getNumSpeedSteps();
- mPowerCpuNormal = new double[speedSteps];
- mSpeedStepTimes = new long[speedSteps];
- for (int p = 0; p < speedSteps; p++) {
- mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
- }
- }
-
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- final int speedSteps = mSpeedStepTimes.length;
-
- long totalTimeAtSpeeds = 0;
- for (int step = 0; step < speedSteps; step++) {
- mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType);
- totalTimeAtSpeeds += mSpeedStepTimes[step];
- }
- totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
-
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
- if (DEBUG && app.cpuTimeMs != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms");
- }
-
- double cpuPowerMaMs = 0;
- for (int step = 0; step < speedSteps; step++) {
- final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
- final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step];
- if (DEBUG && ratio != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
- + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
- + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
- }
- cpuPowerMaMs += cpuSpeedStepPower;
- }
-
- if (DEBUG && cpuPowerMaMs != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": cpu total power="
- + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000)));
+ app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0);
+ if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
+ + BatteryStatsHelper.makemAh(app.cpuPowerMah));
}
// Keep track of the package with highest drain.
@@ -108,8 +68,5 @@ public class CpuPowerCalculator extends PowerCalculator {
// Statistics may not have been gathered yet.
app.cpuTimeMs = app.cpuFgTimeMs;
}
-
- // Convert the CPU power to mAh
- app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9ca937c167fe..959d249c3ecd 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -179,8 +179,18 @@ public class ZygoteInit {
static void preload() {
Log.d(TAG, "begin preload");
- preloadClasses();
- preloadResources();
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses");
+ preloadClasses();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources");
+ preloadResources();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
@@ -266,6 +276,7 @@ public class ZygoteInit {
}
try {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClass " + line);
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
@@ -289,6 +300,8 @@ public class ZygoteInit {
throw (RuntimeException) t;
}
throw new RuntimeException(t);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
}
}
@@ -302,7 +315,9 @@ public class ZygoteInit {
runtime.setTargetHeapUtilization(defaultUtilization);
// Fill in dex caches with classes, fields, and methods brought in by preloading.
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
runtime.preloadDexCaches();
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Bring back root. We'll need it later if we're in the zygote.
if (droppedPriviliges) {
@@ -564,41 +579,56 @@ public class ZygoteInit {
public static void main(String argv[]) {
try {
- RuntimeInit.enableDdms();
- // Start profiling the zygote initialization.
- SamplingProfilerIntegration.start();
-
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
- for (int i = 1; i < argv.length; i++) {
- if ("start-system-server".equals(argv[i])) {
- startSystemServer = true;
- } else if (argv[i].startsWith(ABI_LIST_ARG)) {
- abiList = argv[i].substring(ABI_LIST_ARG.length());
- } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
- socketName = argv[i].substring(SOCKET_NAME_ARG.length());
- } else {
- throw new RuntimeException("Unknown command line argument: " + argv[i]);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
+ RuntimeInit.enableDdms();
+ // Start profiling the zygote initialization.
+ SamplingProfilerIntegration.start();
+
+ for (int i = 1; i < argv.length; i++) {
+ if ("start-system-server".equals(argv[i])) {
+ startSystemServer = true;
+ } else if (argv[i].startsWith(ABI_LIST_ARG)) {
+ abiList = argv[i].substring(ABI_LIST_ARG.length());
+ } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
+ socketName = argv[i].substring(SOCKET_NAME_ARG.length());
+ } else {
+ throw new RuntimeException("Unknown command line argument: " + argv[i]);
+ }
}
- }
- if (abiList == null) {
- throw new RuntimeException("No ABI list supplied.");
- }
+ if (abiList == null) {
+ throw new RuntimeException("No ABI list supplied.");
+ }
- registerZygoteSocket(socketName);
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
- SystemClock.uptimeMillis());
- preload();
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
- SystemClock.uptimeMillis());
+ registerZygoteSocket(socketName);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
+ EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
+ SystemClock.uptimeMillis());
+ preload();
+ EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
+ SystemClock.uptimeMillis());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
- // Finish profiling the zygote initialization.
- SamplingProfilerIntegration.writeZygoteSnapshot();
+ // Finish profiling the zygote initialization.
+ SamplingProfilerIntegration.writeZygoteSnapshot();
- // Do an initial gc to clean up after startup
- gcAndFinalize();
+ // Do an initial gc to clean up after startup
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
+ gcAndFinalize();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 8db363dadfa9..ce5bc908814c 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -29,10 +29,10 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ActionMenuView;
+import android.widget.ForwardingListener;
import android.widget.ListPopupWindow;
import android.widget.TextView;
import android.widget.Toast;
-import android.widget.ListPopupWindow.ForwardingListener;
/**
* @hide
@@ -320,7 +320,7 @@ public class ActionMenuItemView extends TextView
}
@Override
- public ListPopupWindow getPopup() {
+ public ShowableListMenu getPopup() {
if (mPopupCallback != null) {
return mPopupCallback.getPopup();
}
@@ -331,7 +331,7 @@ public class ActionMenuItemView extends TextView
protected boolean onForwardingStarted() {
// Call the invoker, then check if the expected popup is showing.
if (mItemInvoker != null && mItemInvoker.invokeItem(mItemData)) {
- final ListPopupWindow popup = getPopup();
+ final ShowableListMenu popup = getPopup();
return popup != null && popup.isShowing();
}
return false;
@@ -339,7 +339,7 @@ public class ActionMenuItemView extends TextView
@Override
protected boolean onForwardingStopped() {
- final ListPopupWindow popup = getPopup();
+ final ShowableListMenu popup = getPopup();
if (popup != null) {
popup.dismiss();
return true;
@@ -349,6 +349,6 @@ public class ActionMenuItemView extends TextView
}
public static abstract class PopupCallback {
- public abstract ListPopupWindow getPopup();
+ public abstract ShowableListMenu getPopup();
}
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 29ac3f349d0a..25263932bb75 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -43,11 +43,13 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
private TextView mTitleView;
private CheckBox mCheckBox;
private TextView mShortcutView;
+ private ImageView mSubMenuArrowView;
private Drawable mBackground;
private int mTextAppearance;
private Context mTextAppearanceContext;
private boolean mPreserveIconSpacing;
+ private Drawable mSubMenuArrow;
private int mMenuType;
@@ -68,6 +70,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
mPreserveIconSpacing = a.getBoolean(
com.android.internal.R.styleable.MenuView_preserveIconSpacing, false);
mTextAppearanceContext = context;
+ mSubMenuArrow = a.getDrawable(com.android.internal.R.styleable.MenuView_subMenuArrow);
a.recycle();
}
@@ -77,7 +80,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
}
public ListMenuItemView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, com.android.internal.R.attr.listMenuViewStyle);
}
@Override
@@ -93,6 +96,10 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
}
mShortcutView = (TextView) findViewById(com.android.internal.R.id.shortcut);
+ mSubMenuArrowView = (ImageView) findViewById(com.android.internal.R.id.submenuarrow);
+ if (mSubMenuArrowView != null) {
+ mSubMenuArrowView.setImageDrawable(mSubMenuArrow);
+ }
}
public void initialize(MenuItemImpl itemData, int menuType) {
@@ -106,6 +113,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
setIcon(itemData.getIcon());
setEnabled(itemData.isEnabled());
+ setSubMenuArrowVisible(itemData.hasSubMenu());
}
public void setForceShowIcon(boolean forceShow) {
@@ -186,6 +194,12 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
compoundButton.setChecked(checked);
}
+ private void setSubMenuArrowVisible(boolean hasSubmenu) {
+ if (mSubMenuArrowView != null) {
+ mSubMenuArrowView.setVisibility(hasSubmenu ? View.VISIBLE : View.GONE);
+ }
+ }
+
public void setShortcut(boolean showShortcut, char shortcutKey) {
final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
? VISIBLE : GONE;
diff --git a/core/java/com/android/internal/view/menu/MenuAdapter.java b/core/java/com/android/internal/view/menu/MenuAdapter.java
new file mode 100644
index 000000000000..1e03b1f8b971
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/MenuAdapter.java
@@ -0,0 +1,109 @@
+/*
+ * 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.internal.view.menu;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.util.ArrayList;
+
+public class MenuAdapter extends BaseAdapter {
+ static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
+
+ MenuBuilder mAdapterMenu;
+
+ private int mExpandedIndex = -1;
+
+ private boolean mForceShowIcon;
+ private final boolean mOverflowOnly;
+ private final LayoutInflater mInflater;
+
+ public MenuAdapter(MenuBuilder menu, LayoutInflater inflater, boolean overflowOnly) {
+ mOverflowOnly = overflowOnly;
+ mInflater = inflater;
+ mAdapterMenu = menu;
+ findExpandedIndex();
+ }
+
+ public void setForceShowIcon(boolean forceShow) {
+ mForceShowIcon = forceShow;
+ }
+
+ public int getCount() {
+ ArrayList<MenuItemImpl> items = mOverflowOnly ?
+ mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
+ if (mExpandedIndex < 0) {
+ return items.size();
+ }
+ return items.size() - 1;
+ }
+
+ public MenuBuilder getAdapterMenu() {
+ return mAdapterMenu;
+ }
+
+ public MenuItemImpl getItem(int position) {
+ ArrayList<MenuItemImpl> items = mOverflowOnly ?
+ mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
+ if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
+ position++;
+ }
+ return items.get(position);
+ }
+
+ public long getItemId(int position) {
+ // Since a menu item's ID is optional, we'll use the position as an
+ // ID for the item in the AdapterView
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
+ }
+
+ MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+ if (mForceShowIcon) {
+ ((ListMenuItemView) convertView).setForceShowIcon(true);
+ }
+ itemView.initialize(getItem(position), 0);
+ return convertView;
+ }
+
+ void findExpandedIndex() {
+ final MenuItemImpl expandedItem = mAdapterMenu.getExpandedItem();
+ if (expandedItem != null) {
+ final ArrayList<MenuItemImpl> items = mAdapterMenu.getNonActionItems();
+ final int count = items.size();
+ for (int i = 0; i < count; i++) {
+ final MenuItemImpl item = items.get(i);
+ if (item == expandedItem) {
+ mExpandedIndex = i;
+ return;
+ }
+ }
+ }
+ mExpandedIndex = -1;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ findExpandedIndex();
+ super.notifyDataSetChanged();
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 13654a695fcf..e6bc6c3ae044 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -89,7 +89,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
mContext = context;
mInflater = LayoutInflater.from(context);
mMenu = menu;
- mAdapter = new MenuAdapter(mMenu);
+ mAdapter = new MenuAdapter(mMenu, mInflater, overflowOnly);
mOverflowOnly = overflowOnly;
mPopupStyleAttr = popupStyleAttr;
mPopupStyleRes = popupStyleRes;
@@ -358,73 +358,4 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
@Override
public void onRestoreInstanceState(Parcelable state) {
}
-
- private class MenuAdapter extends BaseAdapter {
- private MenuBuilder mAdapterMenu;
- private int mExpandedIndex = -1;
-
- public MenuAdapter(MenuBuilder menu) {
- mAdapterMenu = menu;
- findExpandedIndex();
- }
-
- public int getCount() {
- ArrayList<MenuItemImpl> items = mOverflowOnly ?
- mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
- if (mExpandedIndex < 0) {
- return items.size();
- }
- return items.size() - 1;
- }
-
- public MenuItemImpl getItem(int position) {
- ArrayList<MenuItemImpl> items = mOverflowOnly ?
- mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
- if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
- position++;
- }
- return items.get(position);
- }
-
- public long getItemId(int position) {
- // Since a menu item's ID is optional, we'll use the position as an
- // ID for the item in the AdapterView
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
- }
-
- MenuView.ItemView itemView = (MenuView.ItemView) convertView;
- if (mForceShowIcon) {
- ((ListMenuItemView) convertView).setForceShowIcon(true);
- }
- itemView.initialize(getItem(position), 0);
- return convertView;
- }
-
- void findExpandedIndex() {
- final MenuItemImpl expandedItem = mMenu.getExpandedItem();
- if (expandedItem != null) {
- final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
- final int count = items.size();
- for (int i = 0; i < count; i++) {
- final MenuItemImpl item = items.get(i);
- if (item == expandedItem) {
- mExpandedIndex = i;
- return;
- }
- }
- }
- mExpandedIndex = -1;
- }
-
- @Override
- public void notifyDataSetChanged() {
- findExpandedIndex();
- super.notifyDataSetChanged();
- }
- }
}
diff --git a/core/java/com/android/internal/view/menu/ShowableListMenu.java b/core/java/com/android/internal/view/menu/ShowableListMenu.java
new file mode 100644
index 000000000000..ca158fdb690e
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ShowableListMenu.java
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.view.menu;
+
+import android.widget.ListView;
+
+/**
+ * A list menu which can be shown and hidden and which is internally represented by a ListView.
+ */
+public interface ShowableListMenu {
+ public void show();
+
+ public void dismiss();
+
+ public boolean isShowing();
+
+ /**
+ * @return The internal ListView for the visible menu.
+ */
+ public ListView getListView();
+}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 35eeca7fd030..582c4f1dd669 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -19,6 +19,7 @@ import com.android.internal.R;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
import android.widget.ActionMenuPresenter;
import android.widget.ActionMenuView;
@@ -53,6 +54,9 @@ public abstract class AbsActionBarView extends ViewGroup {
protected Animator mVisibilityAnim;
+ private boolean mEatingTouch;
+ private boolean mEatingHover;
+
public AbsActionBarView(Context context) {
this(context, null);
}
@@ -97,6 +101,57 @@ public abstract class AbsActionBarView extends ViewGroup {
}
}
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // ActionBarViews always eat touch events, but should still respect the touch event dispatch
+ // contract. If the normal View implementation doesn't want the events, we'll just silently
+ // eat the rest of the gesture without reporting the events to the default implementation
+ // since that's what it expects.
+
+ final int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mEatingTouch = false;
+ }
+
+ if (!mEatingTouch) {
+ final boolean handled = super.onTouchEvent(ev);
+ if (action == MotionEvent.ACTION_DOWN && !handled) {
+ mEatingTouch = true;
+ }
+ }
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mEatingTouch = false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onHoverEvent(MotionEvent ev) {
+ // Same deal as onTouchEvent() above. Eat all hover events, but still
+ // respect the touch event dispatch contract.
+
+ final int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_HOVER_ENTER) {
+ mEatingHover = false;
+ }
+
+ if (!mEatingHover) {
+ final boolean handled = super.onHoverEvent(ev);
+ if (action == MotionEvent.ACTION_HOVER_ENTER && !handled) {
+ mEatingHover = true;
+ }
+ }
+
+ if (action == MotionEvent.ACTION_HOVER_EXIT
+ || action == MotionEvent.ACTION_CANCEL) {
+ mEatingHover = false;
+ }
+
+ return true;
+ }
+
/**
* Sets whether the bar should be split right now, no questions asked.
* @param split true if the bar should split
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 073a2ad92ca7..051845ff7970 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1178,7 +1178,7 @@ public class LockPatternUtils {
* @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
*/
public void requireCredentialEntry(int userId) {
- requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
}
/**
@@ -1260,7 +1260,7 @@ public class LockPatternUtils {
value = { STRONG_AUTH_NOT_REQUIRED,
STRONG_AUTH_REQUIRED_AFTER_BOOT,
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1275,14 +1275,14 @@ public class LockPatternUtils {
public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
/**
- * Strong authentication is required because a device admin has requested it.
+ * Strong authentication is required because a device admin has temporarily requested it.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
/**
- * Some authentication is required because the user has temporarily disabled trust.
+ * Strong authentication is required because the user has temporarily requested it.
*/
- public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+ public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
/**
* Strong authentication is required because the user has been locked out after too many
@@ -1291,7 +1291,6 @@ public class LockPatternUtils {
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
- private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
@@ -1333,7 +1332,7 @@ public class LockPatternUtils {
* current strong authentication requirements.
*/
public boolean isFingerprintAllowedForUser(int userId) {
- return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+ return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
}
/**
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f7a2f9fb53f5..e4bc80013b9c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_DALVIK
#define LOG_TAG "AndroidRuntime"
//#define LOG_NDEBUG 0
@@ -23,6 +24,7 @@
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <utils/misc.h>
+#include <utils/Trace.h>
#include <binder/Parcel.h>
#include <utils/threads.h>
#include <cutils/properties.h>
@@ -1437,6 +1439,7 @@ static const RegJNIRec gRegJNI[] = {
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
+ ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 414cbb4db835..aef70be4922a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -83,6 +83,14 @@ static void SigChldHandler(int /*signal_number*/) {
pid_t pid;
int status;
+ // It's necessary to save and restore the errno during this function.
+ // Since errno is stored per thread, changing it here modifies the errno
+ // on the thread on which this signal handler executes. If a signal occurs
+ // between a call and an errno check, it's possible to get the errno set
+ // here.
+ // See b/23572286 for extra information.
+ int saved_errno = errno;
+
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// Log process-death status that we care about. In general it is
// not safe to call LOG(...) from a signal handler because of
@@ -118,6 +126,8 @@ static void SigChldHandler(int /*signal_number*/) {
if (pid < 0 && errno != ECHILD) {
ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
}
+
+ errno = saved_errno;
}
// Configures the SIGCHLD handler for the zygote process. This is configured
diff --git a/core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml b/core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml
new file mode 100644
index 000000000000..2dd0540f8bb5
--- /dev/null
+++ b/core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="25.0dp"
+ android:viewportHeight="25.0"
+ android:viewportWidth="24.0"
+ android:width="25.0dp"
+ android:tint="?attr/colorControlNormal"
+ android:autoMirrored="true">
+
+ <group
+ android:name="arrow"
+ android:rotation="90.0"
+ android:pivotX="12.0"
+ android:pivotY="13.0"
+ android:translateY="1.0">
+ <path android:fillColor="#000000" android:pathData="M7,14 L12,9 L17,14 L7,14 Z" />
+ <path android:pathData="M0,0 L24,0 L24,24 L0,24 L0,0 Z" />
+ </group>
+</vector> \ No newline at end of file
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index 0bc636f0c4af..8b8c93afffbd 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -57,6 +57,15 @@
</RelativeLayout>
+ <ImageView
+ android:id="@+id/submenuarrow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="8dp"
+ android:scaleType="center"
+ android:visibility="gone" />
+
<!-- Checkbox, and/or radio button will be inserted here. -->
</com.android.internal.view.menu.ListMenuItemView>
diff --git a/core/res/res/values-ca-watch/strings.xml b/core/res/res/values-ca-watch/strings.xml
index b01ca630166e..231450fec3c2 100644
--- a/core/res/res/values-ca-watch/strings.xml
+++ b/core/res/res/values-ca-watch/strings.xml
@@ -31,7 +31,7 @@
<string name="permgrouplab_camerawear" msgid="4543951283103407017">"fer fotos i enregistrar vídeos"</string>
<string name="permgrouplab_phonewear" msgid="134365036753766126">"fer i gestionar trucades telefòniques"</string>
<string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accedir a les dades del sensor sobre els signes vitals"</string>
- <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ser la barra d\'estat"</string>
+ <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"aparèixer a la barra d\'estat"</string>
<string name="permlab_bodySensorswear" msgid="7857941041202791873">"accedir als sensors corporals (com ara monitors de freqüència cardíaca)"</string>
<string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"accedir a la ubicació precisa (basada en el GPS i la xarxa)"</string>
<string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"accedir a la ubicació aproximada (basada en la xarxa)"</string>
@@ -40,7 +40,7 @@
<string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gestionar els propietaris del perfil i del dispositiu"</string>
<string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"canviar l\'estat de WiMAX"</string>
<string name="permlab_handoverStatuswear" msgid="4835786819716499249">"rebre l\'estat de la transferència d\'Android Beam"</string>
- <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"indicar la ruta de sortida del contingut multimèdia"</string>
+ <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"indicar la sortida del fitxer multimèdia"</string>
<string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"llegir les sessions d\'instal·lació"</string>
- <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"sol·licitar els paquets d\'instal·lació"</string>
+ <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"sol·licitar la instal·lació de paquets"</string>
</resources>
diff --git a/core/res/res/values-el-watch/strings.xml b/core/res/res/values-el-watch/strings.xml
index 8081013177ff..83d9c3dae2e2 100644
--- a/core/res/res/values-el-watch/strings.xml
+++ b/core/res/res/values-el-watch/strings.xml
@@ -42,5 +42,5 @@
<string name="permlab_handoverStatuswear" msgid="4835786819716499249">"λήψη κατάστασης μεταφοράς Android Beam"</string>
<string name="permlab_route_media_outputwear" msgid="8737024341474587192">"δρομολόγηση εξόδου μέσων"</string>
<string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ανάγνωση περιόδων σύνδεσης εγκατάστασης"</string>
- <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"αίτημα εγκατάστασης πακέτων."</string>
+ <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"αίτημα εγκατάστασης πακέτων"</string>
</resources>
diff --git a/core/res/res/values-eu-rES-watch/strings.xml b/core/res/res/values-eu-rES-watch/strings.xml
index 011105e4faa5..0fca702c9e34 100644
--- a/core/res/res/values-eu-rES-watch/strings.xml
+++ b/core/res/res/values-eu-rES-watch/strings.xml
@@ -26,7 +26,7 @@
<string name="permgrouplab_locationwear" msgid="6275317222482780209">"Atzitu erlojuaren kokapena"</string>
<string name="permgrouplab_calendarwear" msgid="441900844045065081">"Atzitu egutegia"</string>
<string name="permgrouplab_smswear" msgid="6849506550342974220">"Bidali eta ikusi SMS mezuak"</string>
- <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Atzitu erlojuko argazkiak, multimedia-elementuak eta fitxategiak"</string>
+ <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Atzitu erlojuko argazkiak, multimedia-edukia eta fitxategiak"</string>
<string name="permgrouplab_microphonewear" msgid="1047561180980891136">"Grabatu audioa"</string>
<string name="permgrouplab_camerawear" msgid="4543951283103407017">"Atera argazkiak eta grabatu bideoak"</string>
<string name="permgrouplab_phonewear" msgid="134365036753766126">"Egin eta kudeatu telefono-deiak"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 43264a7586f2..2bdc9c83532d 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1149,7 +1149,7 @@
<string name="sync_really_delete" msgid="2572600103122596243">"ഇനങ്ങൾ ഇല്ലാതാക്കുക"</string>
<string name="sync_undo_deletes" msgid="2941317360600338602">"ഇല്ലാതാക്കിയവ പഴയപടിയാക്കുക"</string>
<string name="sync_do_nothing" msgid="3743764740430821845">"ഇപ്പോൾ ഒന്നും ചെയ്യേണ്ടതില്ല"</string>
- <string name="choose_account_label" msgid="5655203089746423927">"ഒരു അക്കൗണ്ട് തിരഞ്ഞെടുക്കുക"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"അക്കൗണ്ട് തിരഞ്ഞെടുക്കൂ"</string>
<string name="add_account_label" msgid="2935267344849993553">"ഒരു അക്കൗണ്ട് ചേർക്കുക"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"അക്കൗണ്ട് ചേർക്കുക"</string>
<string name="number_picker_increment_button" msgid="2412072272832284313">"വർദ്ധിപ്പിക്കുക"</string>
diff --git a/core/res/res/values-ne-rNP-watch/strings.xml b/core/res/res/values-ne-rNP-watch/strings.xml
index a38de9997437..1b4ffc9fd23f 100644
--- a/core/res/res/values-ne-rNP-watch/strings.xml
+++ b/core/res/res/values-ne-rNP-watch/strings.xml
@@ -26,7 +26,7 @@
<string name="permgrouplab_locationwear" msgid="6275317222482780209">"यो घडीको स्थान पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_calendarwear" msgid="441900844045065081">"आफ्नो पात्रोमा पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
- <string name="permgrouplab_storagewear" msgid="1003807594193602313">"आफ्नो समयमा फोटो, मिडिया, र फाइलहरू हेर्नुहोस्"</string>
+ <string name="permgrouplab_storagewear" msgid="1003807594193602313">"आफ्नो समयमा तस्बिर, मिडिया, र फाइलहरू हेर्नुहोस्"</string>
<string name="permgrouplab_microphonewear" msgid="1047561180980891136">"अडियो रेकर्ड गर्नुहोस्"</string>
<string name="permgrouplab_camerawear" msgid="4543951283103407017">"तस्बिरहरू खिच्नुहोस् र भिडियो रेकर्ड गर्नुहोस्"</string>
<string name="permgrouplab_phonewear" msgid="134365036753766126">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string>
diff --git a/core/res/res/values-ta-rIN-watch/strings.xml b/core/res/res/values-ta-rIN-watch/strings.xml
index 63e072fb0e25..629ca273b937 100644
--- a/core/res/res/values-ta-rIN-watch/strings.xml
+++ b/core/res/res/values-ta-rIN-watch/strings.xml
@@ -29,7 +29,7 @@
<string name="permgrouplab_storagewear" msgid="1003807594193602313">"உங்கள் வாட்சில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுகும்"</string>
<string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ஆடியோவைப் பதிவுசெய்யும்"</string>
<string name="permgrouplab_camerawear" msgid="4543951283103407017">"படங்களை எடுக்கும், வீடியோவைப் பதிவுசெய்யும்"</string>
- <string name="permgrouplab_phonewear" msgid="134365036753766126">"மொபைல் அழைப்புகளைச் செய்யும், பெறும்"</string>
+ <string name="permgrouplab_phonewear" msgid="134365036753766126">"மொபைல் அழைப்புகளைச் செய்யும், நிர்வகிக்கும்"</string>
<string name="permgrouplab_sensorswear" msgid="1429324744329327663">"உங்கள் உடலியக்கக் குறிகள் பற்றிய உணர்வித் தரவை அணுகும்"</string>
<string name="permlab_statusBarServicewear" msgid="2469402818964691034">"நிலைப் பட்டியில் இருக்கும்"</string>
<string name="permlab_bodySensorswear" msgid="7857941041202791873">"உடல் உணர்விகளை (இதயத் துடிப்பு மானிட்டர்கள் போன்றவை) அணுகும்"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index aa469496e6c6..e6e20f163406 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -429,7 +429,7 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"فنگر پرنٹ اسٹور نہیں کیا جا سکتا ہے۔ براہ کرم ایک موجودہ فنگر پرنٹ ہٹائیں۔"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"فنگر پرنٹ کی میعاد ختم ہوگئی۔ دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"فنگر پرنٹ کی کارروائی منسوخ ہوگئی۔"</string>
- <string name="fingerprint_error_lockout" msgid="5536934748136933450">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوباہ کوشش کریں۔"</string>
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 61af6c5d1892..59d1a7c62e2a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -639,6 +639,8 @@ i
<attr name="imageButtonStyle" format="reference" />
<!-- The style resource to use for an ImageButton that is an image well. -->
<attr name="imageWellStyle" format="reference" />
+ <!-- Default menu-style ListView style. -->
+ <attr name="listMenuViewStyle" format="reference" />
<!-- Default ListView style. -->
<attr name="listViewStyle" format="reference" />
<!-- ListView with white background. -->
@@ -3784,6 +3786,8 @@ i
<attr name="itemIconDisabledAlpha" format="float" />
<!-- Whether space should be reserved in layout when an icon is missing. -->
<attr name="preserveIconSpacing" format="boolean" />
+ <!-- Drawable for the arrow icon indicating a particular item is a submenu. -->
+ <attr name="subMenuArrow" format="reference" />
</declare-styleable>
<declare-styleable name="IconMenuView">
<!-- Defines the height of each row. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d2089cdad73b..c89b31bd7e65 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2660,6 +2660,9 @@
=============================================================== -->
<eat-comment />
+ <public type="attr" name="listMenuViewStyle" />
+ <public type="attr" name="subMenuArrow" />
+
<public type="style" name="Theme.Material.DayNight" />
<public type="style" name="Theme.Material.DayNight.DarkActionBar" />
<public type="style" name="Theme.Material.DayNight.Dialog" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2369c9be158d..5dc14e301704 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -685,6 +685,10 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.ListView.White"/>
+ <style name="Widget.Material.ListMenuView">
+ <item name="subMenuArrow">@drawable/ic_arrow_drop_right_black_24dp</item>
+ </style>
+
<style name="Widget.Material.PopupWindow" parent="Widget.PopupWindow"/>
<style name="Widget.Material.PopupWindow.ActionMode">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e04c7438a224..98c9f77523b1 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -158,6 +158,7 @@
<java-symbol type="id" name="shortcut" />
<java-symbol type="id" name="skip_button" />
<java-symbol type="id" name="split_action_bar" />
+ <java-symbol type="id" name="submenuarrow" />
<java-symbol type="id" name="submit_area" />
<java-symbol type="id" name="switch_new" />
<java-symbol type="id" name="switch_old" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index e406ae06d96c..30101909f0b4 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -238,6 +238,7 @@ please see themes_device_defaults.xml.
<item name="gridViewStyle">@style/Widget.Material.GridView</item>
<item name="imageButtonStyle">@style/Widget.Material.ImageButton</item>
<item name="imageWellStyle">@style/Widget.Material.ImageWell</item>
+ <item name="listMenuViewStyle">@style/Widget.Material.ListMenuView</item>
<item name="listViewStyle">@style/Widget.Material.ListView</item>
<item name="listViewWhiteStyle">@style/Widget.Material.ListView.White</item>
<item name="popupWindowStyle">@style/Widget.Material.PopupWindow</item>
@@ -594,6 +595,7 @@ please see themes_device_defaults.xml.
<item name="gridViewStyle">@style/Widget.Material.Light.GridView</item>
<item name="imageButtonStyle">@style/Widget.Material.Light.ImageButton</item>
<item name="imageWellStyle">@style/Widget.Material.Light.ImageWell</item>
+ <item name="listMenuViewStyle">@style/Widget.Material.ListMenuView</item>
<item name="listViewStyle">@style/Widget.Material.Light.ListView</item>
<item name="listViewWhiteStyle">@style/Widget.Material.Light.ListView.White</item>
<item name="popupWindowStyle">@style/Widget.Material.Light.PopupWindow</item>
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
new file mode 100644
index 000000000000..fd8f23abc45c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.view;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class HandlerActionQueueTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testPostAndRemove() {
+ HandlerActionQueue runQueue = new HandlerActionQueue();
+ MockRunnable runnable1 = new MockRunnable();
+ MockRunnable runnable2 = new MockRunnable();
+ MockRunnable runnable3 = new MockRunnable();
+
+ runQueue.post(runnable1);
+ runQueue.post(runnable1);
+ runQueue.post(runnable2);
+ runQueue.postDelayed(runnable1, 100);
+ runQueue.postDelayed(null, 500);
+ assertEquals(5, runQueue.size());
+ assertEquals(0, runQueue.getDelay(0));
+ assertEquals(0, runQueue.getDelay(1));
+ assertEquals(0, runQueue.getDelay(2));
+ assertEquals(100, runQueue.getDelay(3));
+ assertEquals(500, runQueue.getDelay(4));
+ assertEquals(500, runQueue.getDelay(4));
+ assertEquals(runnable1, runQueue.getRunnable(0));
+ assertEquals(runnable1, runQueue.getRunnable(1));
+ assertEquals(runnable2, runQueue.getRunnable(2));
+ assertEquals(runnable1, runQueue.getRunnable(3));
+ assertEquals(null, runQueue.getRunnable(4));
+
+ runQueue.removeCallbacks(runnable1);
+ assertEquals(2, runQueue.size());
+ assertEquals(0, runQueue.getDelay(0));
+ assertEquals(500, runQueue.getDelay(1));
+ assertEquals(runnable2, runQueue.getRunnable(0));
+ assertEquals(null, runQueue.getRunnable(1));
+
+ try {
+ assertNull(runQueue.getRunnable(2));
+ assertFalse(true);
+ } catch (IndexOutOfBoundsException e) {
+ // Should throw an exception.
+ }
+
+ runQueue.removeCallbacks(runnable3);
+ assertEquals(2, runQueue.size());
+
+ runQueue.removeCallbacks(runnable2);
+ assertEquals(1, runQueue.size());
+ assertEquals(null, runQueue.getRunnable(0));
+
+ runQueue.removeCallbacks(null);
+ assertEquals(0, runQueue.size());
+ }
+
+ private static class MockRunnable implements Runnable {
+ @Override
+ public void run() {
+
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index c5d68bd230c1..ce35b871b8db 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,10 +17,13 @@
package android.graphics;
import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Size;
import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
+import android.util.LocaleList;
import java.util.Locale;
@@ -50,7 +53,7 @@ public class Paint {
private float mCompatScaling;
private float mInvCompatScaling;
- private Locale mLocale;
+ private LocaleList mLocales;
private String mFontFeatureSettings;
/**
@@ -434,7 +437,7 @@ public class Paint {
// setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
// ? HINTING_OFF : HINTING_ON);
mCompatScaling = mInvCompatScaling = 1;
- setTextLocale(Locale.getDefault());
+ setTextLocales(LocaleList.getDefault());
}
/**
@@ -474,7 +477,7 @@ public class Paint {
mInvCompatScaling = 1;
mBidiFlags = BIDI_DEFAULT_LTR;
- setTextLocale(Locale.getDefault());
+ setTextLocales(LocaleList.getDefault());
setElegantTextHeight(false);
mFontFeatureSettings = null;
}
@@ -512,7 +515,7 @@ public class Paint {
mInvCompatScaling = paint.mInvCompatScaling;
mBidiFlags = paint.mBidiFlags;
- mLocale = paint.mLocale;
+ mLocales = paint.mLocales;
mFontFeatureSettings = paint.mFontFeatureSettings;
}
@@ -1174,47 +1177,80 @@ public class Paint {
}
/**
- * Get the text Locale.
+ * Get the text's primary Locale. Note that this is not all of the locale-related information
+ * Paint has. Use {@link #getTextLocales()} to get the complete list.
*
- * @return the paint's Locale used for drawing text, never null.
+ * @return the paint's primary Locale used for drawing text, never null.
*/
+ @NonNull
public Locale getTextLocale() {
- return mLocale;
+ return mLocales.getPrimary();
}
/**
- * Set the text locale.
+ * Get the text locale list.
*
- * The text locale affects how the text is drawn for some languages.
+ * @return the paint's LocaleList used for drawing text, never null or empty.
+ */
+ @NonNull @Size(min=1)
+ public LocaleList getTextLocales() {
+ return mLocales;
+ }
+
+ /**
+ * Set the text locale list to a one-member list consisting of just the locale.
+ *
+ * See {@link #setTextLocales(LocaleList)} for how the locale list affects
+ * the way the text is drawn for some languages.
+ *
+ * @param locale the paint's locale value for drawing text, must not be null.
+ */
+ public void setTextLocale(@NonNull Locale locale) {
+ if (locale == null) {
+ throw new IllegalArgumentException("locale cannot be null");
+ }
+ if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.getPrimary())) {
+ return;
+ }
+ mLocales = new LocaleList(locale);
+ native_setTextLocale(mNativePaint, locale.toString());
+ }
+
+ /**
+ * Set the text locale list.
*
- * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
+ * The text locale list affects how the text is drawn for some languages.
+ *
+ * For example, if the locale list contains {@link Locale#CHINESE} or {@link Locale#CHINA},
* then the text renderer will prefer to draw text using a Chinese font. Likewise,
- * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
- * renderer will prefer to draw text using a Japanese font.
+ * if the locale list contains {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
+ * renderer will prefer to draw text using a Japanese font. If the locale list contains both,
+ * the order those locales appear in the list is considered for deciding the font.
*
* This distinction is important because Chinese and Japanese text both use many
* of the same Unicode code points but their appearance is subtly different for
* each language.
*
- * By default, the text locale is initialized to the system locale (as returned
- * by {@link Locale#getDefault}). This assumes that the text to be rendered will
- * most likely be in the user's preferred language.
+ * By default, the text locale list is initialized to a one-member list just containing the
+ * system locale (as returned by {@link LocaleList#getDefault()}). This assumes that the text to
+ * be rendered will most likely be in the user's preferred language.
*
- * If the actual language of the text is known, then it can be provided to the
- * text renderer using this method. The text renderer may attempt to guess the
+ * If the actual language or languages of the text is/are known, then they can be provided to
+ * the text renderer using this method. The text renderer may attempt to guess the
* language script based on the contents of the text to be drawn independent of
- * the text locale here. Specifying the text locale just helps it do a better
- * job in certain ambiguous cases
+ * the text locale here. Specifying the text locales just helps it do a better
+ * job in certain ambiguous cases.
*
- * @param locale the paint's locale value for drawing text, must not be null.
+ * @param locales the paint's locale list for drawing text, must not be null or empty.
*/
- public void setTextLocale(Locale locale) {
- if (locale == null) {
- throw new IllegalArgumentException("locale cannot be null");
+ public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+ if (locales == null || locales.isEmpty()) {
+ throw new IllegalArgumentException("locales cannot be null or empty");
}
- if (locale.equals(mLocale)) return;
- mLocale = locale;
- native_setTextLocale(mNativePaint, locale.toString());
+ if (locales.equals(mLocales)) return;
+ mLocales = locales;
+ // TODO: Pass the whole LocaleList to native code
+ native_setTextLocale(mNativePaint, locales.getPrimary().toString());
}
/**
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 1cfccc458c88..174722538014 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -726,7 +726,7 @@ public class VectorDrawable extends Drawable {
Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
// Then print all the children groups
for (int i = 0; i < currentGroup.mChildren.size(); i++) {
- Object child = currentGroup.mChildren.get(i);
+ final VObject child = currentGroup.mChildren.get(i);
if (child instanceof VGroup) {
printGroupTree((VGroup) child, level + 1);
}
@@ -783,12 +783,6 @@ public class VectorDrawable extends Drawable {
mThemeAttrs = copy.mThemeAttrs;
mChangingConfigurations = copy.mChangingConfigurations;
mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
- if (copy.mVPathRenderer.mFillPaint != null) {
- mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
- }
- if (copy.mVPathRenderer.mStrokePaint != null) {
- mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
- }
mTint = copy.mTint;
mTintMode = copy.mTintMode;
mAutoMirrored = copy.mAutoMirrored;
@@ -913,13 +907,7 @@ public class VectorDrawable extends Drawable {
*/
// Variables that only used temporarily inside the draw() call, so there
// is no need for deep copying.
- private final Path mPath;
- private final Path mRenderPath;
- private final Matrix mFinalPathMatrix = new Matrix();
-
- private Paint mStrokePaint;
- private Paint mFillPaint;
- private PathMeasure mPathMeasure;
+ private final TempState mTempState = new TempState();
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
@@ -935,12 +923,10 @@ public class VectorDrawable extends Drawable {
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
- final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+ final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
public VPathRenderer() {
mRootGroup = new VGroup();
- mPath = new Path();
- mRenderPath = new Path();
}
public void setRootAlpha(int alpha) {
@@ -964,8 +950,6 @@ public class VectorDrawable extends Drawable {
public VPathRenderer(VPathRenderer copy) {
mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
- mPath = new Path(copy.mPath);
- mRenderPath = new Path(copy.mRenderPath);
mBaseWidth = copy.mBaseWidth;
mBaseHeight = copy.mBaseHeight;
mViewportWidth = copy.mViewportWidth;
@@ -981,215 +965,28 @@ public class VectorDrawable extends Drawable {
}
public boolean canApplyTheme() {
- // If one of the paths can apply theme, then return true;
- return recursiveCanApplyTheme(mRootGroup);
- }
-
- private boolean recursiveCanApplyTheme(VGroup currentGroup) {
- // We can do a tree traverse here, if there is one path return true,
- // then we return true for the whole tree.
- final ArrayList<Object> children = currentGroup.mChildren;
-
- for (int i = 0; i < children.size(); i++) {
- Object child = children.get(i);
- if (child instanceof VGroup) {
- VGroup childGroup = (VGroup) child;
- if (childGroup.canApplyTheme()
- || recursiveCanApplyTheme(childGroup)) {
- return true;
- }
- } else if (child instanceof VPath) {
- VPath childPath = (VPath) child;
- if (childPath.canApplyTheme()) {
- return true;
- }
- }
- }
- return false;
+ return mRootGroup.canApplyTheme();
}
public void applyTheme(Theme t) {
- // Apply theme to every path of the tree.
- recursiveApplyTheme(mRootGroup, t);
- }
-
- private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
- // We can do a tree traverse here, apply theme to all paths which
- // can apply theme.
- final ArrayList<Object> children = currentGroup.mChildren;
- for (int i = 0; i < children.size(); i++) {
- Object child = children.get(i);
- if (child instanceof VGroup) {
- VGroup childGroup = (VGroup) child;
- if (childGroup.canApplyTheme()) {
- childGroup.applyTheme(t);
- }
- recursiveApplyTheme(childGroup, t);
- } else if (child instanceof VPath) {
- VPath childPath = (VPath) child;
- if (childPath.canApplyTheme()) {
- childPath.applyTheme(t);
- }
- }
- }
- }
-
- private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
- Canvas canvas, int w, int h, ColorFilter filter) {
- // Calculate current group's matrix by preConcat the parent's and
- // and the current one on the top of the stack.
- // Basically the Mfinal = Mviewport * M0 * M1 * M2;
- // Mi the local matrix at level i of the group tree.
- currentGroup.mStackedMatrix.set(currentMatrix);
- currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
-
- // Save the current clip information, which is local to this group.
- canvas.save();
- // 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);
- if (child instanceof VGroup) {
- VGroup childGroup = (VGroup) child;
- drawGroupTree(childGroup, currentGroup.mStackedMatrix,
- canvas, w, h, filter);
- } else if (child instanceof VPath) {
- VPath childPath = (VPath) child;
- drawPath(currentGroup, childPath, canvas, w, h, filter);
- }
- }
- canvas.restore();
+ mRootGroup.applyTheme(t);
}
public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
- // Travese the tree in pre-order to draw.
- drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvas, w, h, filter);
- }
-
- private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h,
- ColorFilter filter) {
final float scaleX = w / mViewportWidth;
final float scaleY = h / mViewportHeight;
- final float minScale = Math.min(scaleX, scaleY);
- final Matrix groupStackedMatrix = vGroup.mStackedMatrix;
-
- mFinalPathMatrix.set(groupStackedMatrix);
- mFinalPathMatrix.postScale(scaleX, scaleY);
-
- final float matrixScale = getMatrixScale(groupStackedMatrix);
- if (matrixScale == 0) {
- // When either x or y is scaled to 0, we don't need to draw anything.
- return;
- }
- vPath.toPath(mPath);
- final Path path = mPath;
-
- mRenderPath.reset();
-
- if (vPath.isClipPath()) {
- mRenderPath.addPath(path, mFinalPathMatrix);
- canvas.clipPath(mRenderPath);
- } else {
- VFullPath fullPath = (VFullPath) vPath;
- if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
- float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
- float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
-
- if (mPathMeasure == null) {
- mPathMeasure = new PathMeasure();
- }
- mPathMeasure.setPath(mPath, false);
-
- float len = mPathMeasure.getLength();
- start = start * len;
- end = end * len;
- path.reset();
- if (start > end) {
- mPathMeasure.getSegment(start, len, path, true);
- mPathMeasure.getSegment(0f, end, path, true);
- } else {
- mPathMeasure.getSegment(start, end, path, true);
- }
- path.rLineTo(0, 0); // fix bug in measure
- }
- mRenderPath.addPath(path, mFinalPathMatrix);
-
- if (fullPath.mFillColor != Color.TRANSPARENT) {
- if (mFillPaint == null) {
- mFillPaint = new Paint();
- mFillPaint.setStyle(Paint.Style.FILL);
- mFillPaint.setAntiAlias(true);
- }
-
- final Paint fillPaint = mFillPaint;
- fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
- fillPaint.setColorFilter(filter);
- canvas.drawPath(mRenderPath, fillPaint);
- }
-
- if (fullPath.mStrokeColor != Color.TRANSPARENT) {
- if (mStrokePaint == null) {
- mStrokePaint = new Paint();
- mStrokePaint.setStyle(Paint.Style.STROKE);
- mStrokePaint.setAntiAlias(true);
- }
-
- final Paint strokePaint = mStrokePaint;
- if (fullPath.mStrokeLineJoin != null) {
- strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
- }
-
- if (fullPath.mStrokeLineCap != null) {
- strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
- }
-
- strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
- strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
- strokePaint.setColorFilter(filter);
- final float finalStrokeScale = minScale * matrixScale;
- strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
- canvas.drawPath(mRenderPath, strokePaint);
- }
- }
- }
-
- private float getMatrixScale(Matrix groupStackedMatrix) {
- // Given unit vectors A = (0, 1) and B = (1, 0).
- // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
- // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
- // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
- // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
- //
- // For non-skew case, which is most of the cases, matrix scale is computing exactly the
- // scale on x and y axis, and take the minimal of these two.
- // For skew case, an unit square will mapped to a parallelogram. And this function will
- // return the minimal height of the 2 bases.
- float[] unitVectors = new float[] {0, 1, 1, 0};
- groupStackedMatrix.mapVectors(unitVectors);
- float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
- float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
- float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
- unitVectors[2], unitVectors[3]);
- float maxScale = MathUtils.max(scaleX, scaleY);
-
- float matrixScale = 0;
- if (maxScale > 0) {
- matrixScale = MathUtils.abs(crossProduct) / maxScale;
- }
- if (DBG_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
- }
- return matrixScale;
+ mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY);
}
}
- private static class VGroup {
+ private static class VGroup implements VObject {
// mStackedMatrix is only used temporarily when drawing, it combines all
// the parents' local matrices with the current one.
private final Matrix mStackedMatrix = new Matrix();
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
- final ArrayList<Object> mChildren = new ArrayList<Object>();
+ final ArrayList<VObject> mChildren = new ArrayList<>();
private float mRotate = 0;
private float mPivotX = 0;
@@ -1223,14 +1020,14 @@ public class VectorDrawable extends Drawable {
mLocalMatrix.set(copy.mLocalMatrix);
- final ArrayList<Object> children = copy.mChildren;
+ final ArrayList<VObject> children = copy.mChildren;
for (int i = 0; i < children.size(); i++) {
- Object copyChild = children.get(i);
+ final VObject copyChild = children.get(i);
if (copyChild instanceof VGroup) {
- VGroup copyGroup = (VGroup) copyChild;
+ final VGroup copyGroup = (VGroup) copyChild;
mChildren.add(new VGroup(copyGroup, targetsMap));
} else {
- VPath newPath = null;
+ final VPath newPath;
if (copyChild instanceof VFullPath) {
newPath = new VFullPath((VFullPath) copyChild);
} else if (copyChild instanceof VClipPath) {
@@ -1257,6 +1054,30 @@ public class VectorDrawable extends Drawable {
return mLocalMatrix;
}
+ @Override
+ public void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
+ ColorFilter filter, float scaleX, float scaleY) {
+ // Calculate current group's matrix by preConcat the parent's and
+ // and the current one on the top of the stack.
+ // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+ // Mi the local matrix at level i of the group tree.
+ mStackedMatrix.set(currentMatrix);
+ mStackedMatrix.preConcat(mLocalMatrix);
+
+ // Save the current clip information, which is local to this group.
+ canvas.save();
+
+ // Draw the group tree in the same order as the XML file.
+ for (int i = 0, count = mChildren.size(); i < count; i++) {
+ final VObject child = mChildren.get(i);
+ child.draw(canvas, temp, mStackedMatrix, filter, scaleX, scaleY);
+ }
+
+ // Restore the previous clip information.
+ canvas.restore();
+ }
+
+ @Override
public void inflate(Resources res, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(res, theme, attrs,
R.styleable.VectorDrawableGroup);
@@ -1287,18 +1108,39 @@ public class VectorDrawable extends Drawable {
updateLocalMatrix();
}
+ @Override
public boolean canApplyTheme() {
- return mThemeAttrs != null;
+ if (mThemeAttrs != null) {
+ return true;
+ }
+
+ final ArrayList<VObject> children = mChildren;
+ for (int i = 0, count = children.size(); i < count; i++) {
+ final VObject child = children.get(i);
+ if (child.canApplyTheme()) {
+ return true;
+ }
+ }
+
+ return false;
}
+ @Override
public void applyTheme(Theme t) {
- if (mThemeAttrs == null) {
- return;
+ if (mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(mThemeAttrs,
+ R.styleable.VectorDrawableGroup);
+ updateStateFromTypedArray(a);
+ a.recycle();
}
- final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawableGroup);
- updateStateFromTypedArray(a);
- a.recycle();
+ final ArrayList<VObject> children = mChildren;
+ for (int i = 0, count = children.size(); i < count; i++) {
+ final VObject child = children.get(i);
+ if (child.canApplyTheme()) {
+ child.applyTheme(t);
+ }
+ }
}
private void updateLocalMatrix() {
@@ -1407,7 +1249,7 @@ public class VectorDrawable extends Drawable {
/**
* Common Path information for clip path and normal path.
*/
- private static class VPath {
+ private static abstract class VPath implements VObject {
protected PathParser.PathDataNode[] mNodes = null;
String mPathName;
int mChangingConfigurations;
@@ -1422,24 +1264,10 @@ public class VectorDrawable extends Drawable {
mNodes = PathParser.deepCopyNodes(copy.mNodes);
}
- public void toPath(Path path) {
- path.reset();
- if (mNodes != null) {
- PathParser.PathDataNode.nodesToPath(mNodes, path);
- }
- }
-
public String getPathName() {
return mPathName;
}
- public boolean canApplyTheme() {
- return false;
- }
-
- public void applyTheme(Theme t) {
- }
-
public boolean isClipPath() {
return false;
}
@@ -1459,6 +1287,79 @@ public class VectorDrawable extends Drawable {
PathParser.updateNodes(mNodes, nodes);
}
}
+
+ @Override
+ public final void draw(Canvas canvas, TempState temp, Matrix groupStackedMatrix,
+ ColorFilter filter, float scaleX, float scaleY) {
+ final float matrixScale = VPath.getMatrixScale(groupStackedMatrix);
+ if (matrixScale == 0) {
+ // When either x or y is scaled to 0, we don't need to draw anything.
+ return;
+ }
+
+ final Path path = temp.path;
+ path.reset();
+ toPath(temp, path);
+
+ final Matrix pathMatrix = temp.pathMatrix;
+ pathMatrix.set(groupStackedMatrix);
+ pathMatrix.postScale(scaleX, scaleY);
+
+ final Path renderPath = temp.renderPath;
+ renderPath.reset();
+ renderPath.addPath(path, pathMatrix);
+
+ final float minScale = Math.min(scaleX, scaleY);
+ final float strokeScale = minScale * matrixScale;
+ drawPath(temp, renderPath, canvas, filter, strokeScale);
+ }
+
+ /**
+ * Writes the path's nodes to an output Path for rendering.
+ *
+ * @param temp temporary state variables
+ * @param outPath the output path
+ */
+ protected void toPath(TempState temp, Path outPath) {
+ if (mNodes != null) {
+ PathParser.PathDataNode.nodesToPath(mNodes, outPath);
+ }
+ }
+
+ /**
+ * Draws the specified path into the supplied canvas.
+ */
+ protected abstract void drawPath(TempState temp, Path path, Canvas canvas,
+ ColorFilter filter, float strokeScale);
+
+ private static float getMatrixScale(Matrix groupStackedMatrix) {
+ // Given unit vectors A = (0, 1) and B = (1, 0).
+ // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+ // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+ // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+ // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+ //
+ // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+ // scale on x and y axis, and take the minimal of these two.
+ // For skew case, an unit square will mapped to a parallelogram. And this function will
+ // return the minimal height of the 2 bases.
+ float[] unitVectors = new float[] {0, 1, 1, 0};
+ groupStackedMatrix.mapVectors(unitVectors);
+ float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
+ float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
+ float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
+ unitVectors[2], unitVectors[3]);
+ float maxScale = MathUtils.max(scaleX, scaleY);
+
+ float matrixScale = 0;
+ if (maxScale > 0) {
+ matrixScale = MathUtils.abs(crossProduct) / maxScale;
+ }
+ if (DBG_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
+ }
+ return matrixScale;
+ }
}
/**
@@ -1473,6 +1374,13 @@ public class VectorDrawable extends Drawable {
super(copy);
}
+ @Override
+ protected void drawPath(TempState temp, Path renderPath, Canvas canvas, ColorFilter filter,
+ float strokeScale) {
+ canvas.clipPath(renderPath);
+ }
+
+ @Override
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.VectorDrawableClipPath);
@@ -1480,6 +1388,16 @@ public class VectorDrawable extends Drawable {
a.recycle();
}
+ @Override
+ public boolean canApplyTheme() {
+ return false;
+ }
+
+ @Override
+ public void applyTheme(Theme theme) {
+ // No-op.
+ }
+
private void updateStateFromTypedArray(TypedArray a) {
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1574,10 +1492,104 @@ public class VectorDrawable extends Drawable {
}
@Override
- public boolean canApplyTheme() {
- return mThemeAttrs != null;
+ public void toPath(TempState temp, Path path) {
+ super.toPath(temp, path);
+
+ if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
+ VFullPath.applyTrim(temp, path, mTrimPathStart, mTrimPathEnd, mTrimPathOffset);
+ }
+ }
+
+ @Override
+ protected void drawPath(TempState temp, Path path, Canvas canvas, ColorFilter filter,
+ float strokeScale) {
+ drawPathFill(temp, path, canvas, filter);
+ drawPathStroke(temp, path, canvas, filter, strokeScale);
+ }
+
+ /**
+ * Draws this path's fill, if necessary.
+ */
+ private void drawPathFill(TempState temp, Path path, Canvas canvas, ColorFilter filter) {
+ if (mFillColor == Color.TRANSPARENT) {
+ return;
+ }
+
+ if (temp.mFillPaint == null) {
+ temp.mFillPaint = new Paint();
+ temp.mFillPaint.setStyle(Paint.Style.FILL);
+ temp.mFillPaint.setAntiAlias(true);
+ }
+
+ final Paint fillPaint = temp.mFillPaint;
+ fillPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+ fillPaint.setColorFilter(filter);
+ canvas.drawPath(path, fillPaint);
}
+ /**
+ * Draws this path's stroke, if necessary.
+ */
+ private void drawPathStroke(TempState temp, Path path, Canvas canvas, ColorFilter filter,
+ float strokeScale) {
+ if (mStrokeColor == Color.TRANSPARENT) {
+ return;
+ }
+
+ if (temp.mStrokePaint == null) {
+ temp.mStrokePaint = new Paint();
+ temp.mStrokePaint.setStyle(Paint.Style.STROKE);
+ temp.mStrokePaint.setAntiAlias(true);
+ }
+
+ final Paint strokePaint = temp.mStrokePaint;
+ if (mStrokeLineJoin != null) {
+ strokePaint.setStrokeJoin(mStrokeLineJoin);
+ }
+
+ if (mStrokeLineCap != null) {
+ strokePaint.setStrokeCap(mStrokeLineCap);
+ }
+
+ strokePaint.setStrokeMiter(mStrokeMiterlimit);
+ strokePaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+ strokePaint.setColorFilter(filter);
+ strokePaint.setStrokeWidth(mStrokeWidth * strokeScale);
+ canvas.drawPath(path, strokePaint);
+ }
+
+ /**
+ * Applies trimming to the specified path.
+ */
+ private static void applyTrim(TempState temp, Path path, float mTrimPathStart,
+ float mTrimPathEnd, float mTrimPathOffset) {
+ if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
+ // No trimming necessary.
+ return;
+ }
+
+ if (temp.mPathMeasure == null) {
+ temp.mPathMeasure = new PathMeasure();
+ }
+ final PathMeasure pathMeasure = temp.mPathMeasure;
+ pathMeasure.setPath(path, false);
+
+ final float len = pathMeasure.getLength();
+ final float start = len * ((mTrimPathStart + mTrimPathOffset) % 1.0f);
+ final float end = len * ((mTrimPathEnd + mTrimPathOffset) % 1.0f);
+ path.reset();
+ if (start > end) {
+ pathMeasure.getSegment(start, len, path, true);
+ pathMeasure.getSegment(0, end, path, true);
+ } else {
+ pathMeasure.getSegment(start, end, path, true);
+ }
+
+ // Fix bug in measure.
+ path.rLineTo(0, 0);
+ }
+
+ @Override
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.VectorDrawablePath);
@@ -1627,6 +1639,11 @@ public class VectorDrawable extends Drawable {
}
@Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null;
+ }
+
+ @Override
public void applyTheme(Theme t) {
if (mThemeAttrs == null) {
return;
@@ -1718,4 +1735,22 @@ public class VectorDrawable extends Drawable {
mTrimPathOffset = trimPathOffset;
}
}
+
+ static class TempState {
+ final Matrix pathMatrix = new Matrix();
+ final Path path = new Path();
+ final Path renderPath = new Path();
+
+ PathMeasure mPathMeasure;
+ Paint mFillPaint;
+ Paint mStrokePaint;
+ }
+
+ interface VObject {
+ void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
+ ColorFilter filter, float scaleX, float scaleY);
+ void inflate(Resources r, AttributeSet attrs, Theme theme);
+ boolean canApplyTheme();
+ void applyTheme(Theme t);
+ }
}
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 2f287000f746..f682fb8684e8 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -40,10 +40,9 @@ hostSources := $(commonSources)
# For the host
# =====================================================
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
LOCAL_SRC_FILES:= $(hostSources)
@@ -56,13 +55,10 @@ include $(BUILD_HOST_STATIC_LIBRARY)
# =====================================================
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= $(deviceSources)
LOCAL_C_INCLUDES := \
- external/zlib \
system/core/include
LOCAL_STATIC_LIBRARIES := libziparchive libbase
LOCAL_SHARED_LIBRARIES := \
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index a080c7355037..64aa99705b01 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -294,6 +294,11 @@ public final class MtpObjectInfo {
mObjectInfo.mThumbPixWidth = objectInfo.mThumbPixWidth;
}
+ public Builder setObjectHandle(int value) {
+ mObjectInfo.mHandle = value;
+ return this;
+ }
+
public Builder setAssociationDesc(int value) {
mObjectInfo.mAssociationDesc = value;
return this;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 8b9233100827..f8ec8f114313 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -56,6 +56,7 @@ import java.util.Objects;
public class CopyService extends IntentService {
public static final String TAG = "CopyService";
+ public static final boolean DEBUG = false;
private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
@@ -159,6 +160,7 @@ public class CopyService extends IntentService {
// Catch-all to prevent any copy errors from wedging the app.
Log.e(TAG, "Exceptions occurred during copying", e);
} finally {
+ if (DEBUG) Log.d(TAG, "Cleaning up after copy");
ContentProviderClient.releaseQuietly(mSrcClient);
ContentProviderClient.releaseQuietly(mDstClient);
@@ -166,10 +168,12 @@ public class CopyService extends IntentService {
mNotificationManager.cancel(mJobId, 0);
if (mFailedFiles.size() > 0) {
+ Log.e(TAG, mFailedFiles.size() + " files failed to copy");
final Context context = getApplicationContext();
final Intent navigateIntent = new Intent(context, FilesActivity.class);
navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
+ navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode);
navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
final int titleResourceId = (transferMode == TRANSFER_MODE_COPY ?
@@ -186,6 +190,7 @@ public class CopyService extends IntentService {
.setAutoCancel(true);
mNotificationManager.notify(mJobId, 0, errorBuilder.build());
}
+ if (DEBUG) Log.d(TAG, "Done cleaning up");
}
}
@@ -398,6 +403,9 @@ public class CopyService extends IntentService {
*/
private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
throws RemoteException {
+ if (DEBUG) Log.d(TAG, "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")" +
+ " to " + dstDirInfo.displayName + " (" + dstDirInfo.derivedUri + ")");
+
final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
srcInfo.mimeType, srcInfo.displayName);
if (dstUri == null) {
@@ -499,10 +507,28 @@ public class CopyService extends IntentService {
srcFile.checkError();
} catch (IOException e) {
copyError = e;
+
try {
- dstFile.closeWithError(copyError.getMessage());
- } catch (IOException closeError) {
- Log.e(TAG, "Error closing destination", closeError);
+ DocumentInfo info = DocumentInfo.fromUri(getContentResolver(), srcUri);
+ mFailedFiles.add(info);
+ Log.e(TAG, "Error while copying " + info.displayName + " (" + info.derivedUri + ")",
+ copyError);
+ } catch (FileNotFoundException ignore) {
+ // Generate a dummy DocumentInfo so an error still gets reflected in the UI for this
+ // file.
+ DocumentInfo info = new DocumentInfo();
+ info.derivedUri = srcUri;
+ info.displayName = "Unknown [" + srcUri + "]";
+ mFailedFiles.add(info);
+ Log.e(TAG, "Error while copying " + srcUri, copyError);
+ }
+
+ if (dstFile != null) {
+ try {
+ dstFile.closeWithError(copyError.getMessage());
+ } catch (IOException closeError) {
+ Log.e(TAG, "Error closing destination", closeError);
+ }
}
} finally {
// This also ensures the file descriptors are closed.
@@ -510,16 +536,6 @@ public class CopyService extends IntentService {
IoUtils.closeQuietly(dst);
}
- if (copyError != null) {
- // Log errors.
- Log.e(TAG, "Error while copying " + srcUri.toString(), copyError);
- try {
- mFailedFiles.add(DocumentInfo.fromUri(getContentResolver(), srcUri));
- } catch (FileNotFoundException ignore) {
- Log.w(TAG, "Source file gone: " + srcUri, copyError);
- // The source file is gone.
- }
- }
if (copyError != null || mIsCancelled) {
// Clean up half-copied files.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index e15e6e03abc7..ecf03f575b04 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -573,6 +573,9 @@ public class DirectoryFragment extends Fragment {
}
mRecView.setLayoutManager(layout);
+ // TODO: Once b/23691541 is resolved, use a listener within MultiSelectManager instead of
+ // imperatively calling this function.
+ mModel.mSelectionManager.handleLayoutChanged();
// setting layout manager automatically invalidates existing ViewHolders.
mThumbSize = new Point(thumbSize, thumbSize);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index c27cad31fd72..4284f6f9386e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -250,6 +250,10 @@ public final class MultiSelectManager {
notifySelectionChanged();
}
+ public void handleLayoutChanged() {
+ mBandSelectManager.handleLayoutChanged();
+ }
+
/**
* Clears the selection, without notifying anyone.
*/
@@ -1192,6 +1196,18 @@ public final class MultiSelectManager {
}
/**
+ * Handle a change in layout by cleaning up and getting rid of the old model and creating
+ * a new model which will track the new layout.
+ */
+ public void handleLayoutChanged() {
+ mModel.removeOnSelectionChangedListener(this);
+ mModel.stopListening();
+
+ mModel = new BandSelectModel((RuntimeRecyclerViewHelper) mHelper);
+ mModel.addOnSelectionChangedListener(this);
+ }
+
+ /**
* Processes a MotionEvent by starting, ending, or resizing the band select overlay.
* @param e
*/
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fc6117f35d28..cfc232c55973 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -472,6 +473,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
+ private void handleFingerprintLockoutReset() {
+ updateFingerprintListeningState();
+ }
+
private void setFingerprintRunningState(int fingerprintRunningState) {
boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
@@ -681,6 +686,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
};
+ private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
+ = new FingerprintManager.LockoutResetCallback() {
+ @Override
+ public void onLockoutReset() {
+ handleFingerprintLockoutReset();
+ }
+ };
+
private FingerprintManager.AuthenticationCallback mAuthenticationCallback
= new AuthenticationCallback() {
@@ -1003,6 +1016,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
updateFingerprintListeningState();
+ if (mFpm != null) {
+ mFpm.addLockoutResetCallback(mLockoutResetCallback);
+ }
}
private void updateFingerprintListeningState() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
new file mode 100644
index 000000000000..b5694b73a239
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -0,0 +1,100 @@
+/*
+ * 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.mtp;
+
+import android.database.MatrixCursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+
+import java.util.Date;
+
+final class CursorHelper {
+ static final int DUMMY_HANDLE_FOR_ROOT = 0;
+
+ private CursorHelper() {
+ }
+
+ static void addToCursor(MtpRoot root, MatrixCursor.RowBuilder builder) {
+ final Identifier identifier = new Identifier(
+ root.mDeviceId, root.mStorageId, DUMMY_HANDLE_FOR_ROOT);
+ builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+ builder.add(Document.COLUMN_DISPLAY_NAME, root.mDescription);
+ builder.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+ builder.add(Document.COLUMN_LAST_MODIFIED, null);
+ builder.add(Document.COLUMN_FLAGS, 0);
+ builder.add(Document.COLUMN_SIZE,
+ (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+ }
+
+ static void addToCursor(MtpObjectInfo objectInfo, Identifier rootIdentifier,
+ MatrixCursor.RowBuilder builder) {
+ final Identifier identifier = new Identifier(
+ rootIdentifier.mDeviceId, rootIdentifier.mStorageId, objectInfo.getObjectHandle());
+ final String mimeType = formatTypeToMimeType(objectInfo.getFormat());
+
+ int flag = 0;
+ if (objectInfo.getProtectionStatus() == 0) {
+ flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+ DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
+ if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
+ flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
+ }
+ }
+ if (objectInfo.getThumbCompressedSize() > 0) {
+ flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+ }
+
+ builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+ builder.add(Document.COLUMN_DISPLAY_NAME, objectInfo.getName());
+ builder.add(Document.COLUMN_MIME_TYPE, mimeType);
+ builder.add(
+ Document.COLUMN_LAST_MODIFIED,
+ objectInfo.getDateModified() != 0 ? objectInfo.getDateModified() : null);
+ builder.add(Document.COLUMN_FLAGS, flag);
+ builder.add(Document.COLUMN_SIZE, objectInfo.getCompressedSize());
+ }
+
+ static String formatTypeToMimeType(int format) {
+ // TODO: Add complete list of mime types.
+ switch (format) {
+ case MtpConstants.FORMAT_ASSOCIATION:
+ return DocumentsContract.Document.MIME_TYPE_DIR;
+ case MtpConstants.FORMAT_MP3:
+ return "audio/mp3";
+ case MtpConstants.FORMAT_EXIF_JPEG:
+ return "image/jpeg";
+ default:
+ return "application/octet-stream";
+ }
+ }
+
+ static int mimeTypeToFormatType(String mimeType) {
+ // TODO: Add complete list of mime types.
+ switch (mimeType.toLowerCase()) {
+ case Document.MIME_TYPE_DIR:
+ return MtpConstants.FORMAT_ASSOCIATION;
+ case "audio/mp3":
+ return MtpConstants.FORMAT_MP3;
+ case "image/jpeg":
+ return MtpConstants.FORMAT_EXIF_JPEG;
+ default:
+ return MtpConstants.FORMAT_UNDEFINED;
+ }
+ }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index c430def757db..d4c4331267a0 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -19,6 +19,7 @@ package com.android.mtp;
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
@@ -34,6 +35,7 @@ import java.util.LinkedList;
* Loader for MTP document.
* At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
* background thread to load the rest documents and caches its result for next requests.
+ * TODO: Rename this class to ObjectInfoLoader
*/
class DocumentLoader {
static final int NUM_INITIAL_ENTRIES = 10;
@@ -50,13 +52,13 @@ class DocumentLoader {
mResolver = resolver;
}
- private static MtpDocument[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
+ private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
throws IOException {
- final MtpDocument[] documents = new MtpDocument[handles.length];
+ final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length];
for (int i = 0; i < handles.length; i++) {
- documents[i] = manager.getDocument(deviceId, handles[i]);
+ objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]);
}
- return documents;
+ return objectInfos;
}
synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
@@ -66,7 +68,7 @@ class DocumentLoader {
int parentHandle = parent.mObjectHandle;
// Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
// getObjectHandles if we would like to obtain children under the root.
- if (parentHandle == MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+ if (parentHandle == CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
}
task = new LoaderTask(parent, mMtpManager.getObjectHandles(
@@ -89,14 +91,18 @@ class DocumentLoader {
return task.createCursor(mResolver, columnNames);
}
- synchronized void clearCache(int deviceId) {
+ synchronized void clearTasks(int deviceId) {
mTaskList.clearTaskForDevice(deviceId);
}
- synchronized void clearCache() {
+ synchronized void clearCompletedTasks() {
mTaskList.clearCompletedTask();
}
+ synchronized void clearTask(Identifier parentIdentifier) {
+ mTaskList.clearTask(parentIdentifier);
+ }
+
private class BackgroundLoaderThread extends Thread {
@Override
public void run() {
@@ -114,16 +120,16 @@ class DocumentLoader {
deviceId = task.mIdentifier.mDeviceId;
handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
}
- MtpDocument[] documents;
+ MtpObjectInfo[] objectInfos;
try {
- documents = loadDocuments(mMtpManager, deviceId, handles);
+ objectInfos = loadDocuments(mMtpManager, deviceId, handles);
} catch (IOException exception) {
- documents = null;
+ objectInfos = null;
Log.d(MtpDocumentsProvider.TAG, exception.getMessage());
}
synchronized (DocumentLoader.this) {
- if (documents != null) {
- task.fillDocuments(documents);
+ if (objectInfos != null) {
+ task.fillDocuments(objectInfos);
final boolean shouldNotify =
task.mLastNotified.getTime() <
new Date().getTime() - NOTIFY_PERIOD_MS ||
@@ -177,19 +183,30 @@ class DocumentLoader {
}
}
}
+
+ void clearTask(Identifier parentIdentifier) {
+ for (int i = 0; i < size(); i++) {
+ final LoaderTask task = get(i);
+ if (task.mIdentifier.mDeviceId == parentIdentifier.mDeviceId &&
+ task.mIdentifier.mObjectHandle == parentIdentifier.mObjectHandle) {
+ remove(i);
+ return;
+ }
+ }
+ }
}
private static class LoaderTask {
final Identifier mIdentifier;
final int[] mObjectHandles;
- final MtpDocument[] mDocuments;
+ final MtpObjectInfo[] mObjectInfos;
Date mLastNotified;
int mNumLoaded;
LoaderTask(Identifier identifier, int[] objectHandles) {
mIdentifier = identifier;
mObjectHandles = objectHandles;
- mDocuments = new MtpDocument[mObjectHandles.length];
+ mObjectInfos = new MtpObjectInfo[mObjectHandles.length];
mNumLoaded = 0;
mLastNotified = new Date();
}
@@ -199,7 +216,7 @@ class DocumentLoader {
final Identifier rootIdentifier = new Identifier(
mIdentifier.mDeviceId, mIdentifier.mStorageId);
for (int i = 0; i < mNumLoaded; i++) {
- mDocuments[i].addToCursor(rootIdentifier, cursor.newRow());
+ CursorHelper.addToCursor(mObjectInfos[i], rootIdentifier, cursor.newRow());
}
final Bundle extras = new Bundle();
extras.putBoolean(DocumentsContract.EXTRA_LOADING, !completed());
@@ -209,7 +226,7 @@ class DocumentLoader {
}
boolean completed() {
- return mNumLoaded == mDocuments.length;
+ return mNumLoaded == mObjectInfos.length;
}
int[] getUnloadedObjectHandles(int count) {
@@ -224,9 +241,9 @@ class DocumentLoader {
mLastNotified = new Date();
}
- void fillDocuments(MtpDocument[] documents) {
- for (int i = 0; i < documents.length; i++) {
- mDocuments[mNumLoaded++] = documents[i];
+ void fillDocuments(MtpObjectInfo[] objectInfos) {
+ for (int i = 0; i < objectInfos.length; i++) {
+ mObjectInfos[mNumLoaded++] = objectInfos[i];
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
index bd0c837726a8..ae29f526e3ec 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
@@ -41,7 +41,7 @@ class Identifier {
Identifier(int deviceId, int storageId) {
- this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT);
+ this(deviceId, storageId, CursorHelper.DUMMY_HANDLE_FOR_ROOT);
}
Identifier(int deviceId, int storageId, int objectHandle) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
deleted file mode 100644
index c1d9609eeab1..000000000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ /dev/null
@@ -1,132 +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.mtp;
-
-import android.database.MatrixCursor;
-import android.mtp.MtpObjectInfo;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-
-import java.util.Date;
-
-class MtpDocument {
- static final int DUMMY_HANDLE_FOR_ROOT = 0;
-
- private final int mObjectHandle;
- private final int mFormat;
- private final String mName;
- private final Date mDateModified;
- private final int mSize;
- private final int mThumbSize;
- private final boolean mReadOnly;
-
- /**
- * Constructor for root document.
- */
- MtpDocument(MtpRoot root) {
- this(DUMMY_HANDLE_FOR_ROOT,
- 0x3001, // Directory.
- root.mDescription,
- null, // Unknown name.
- (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
- 0, // Total size.
- true); // Writable.
- }
-
- MtpDocument(MtpObjectInfo objectInfo) {
- this(objectInfo.getObjectHandle(),
- objectInfo.getFormat(),
- objectInfo.getName(),
- objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
- objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize(),
- objectInfo.getProtectionStatus() != 0);
- }
-
- MtpDocument(int objectHandle,
- int format,
- String name,
- Date dateModified,
- int size,
- int thumbSize,
- boolean readOnly) {
- this.mObjectHandle = objectHandle;
- this.mFormat = format;
- this.mName = name;
- this.mDateModified = dateModified;
- this.mSize = size;
- this.mThumbSize = thumbSize;
- this.mReadOnly = readOnly;
- }
-
- void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
- final Identifier identifier = new Identifier(
- rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);
- final String mimeType = formatTypeToMimeType(mFormat);
-
- int flag = 0;
- if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
- if (mThumbSize > 0) {
- flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
- }
- if (!mReadOnly) {
- flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
- DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
- }
- }
- if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR && !mReadOnly) {
- flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
- }
-
- builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
- builder.add(Document.COLUMN_DISPLAY_NAME, mName);
- builder.add(Document.COLUMN_MIME_TYPE, mimeType);
- builder.add(
- Document.COLUMN_LAST_MODIFIED,
- mDateModified != null ? mDateModified.getTime() : null);
- builder.add(Document.COLUMN_FLAGS, flag);
- builder.add(Document.COLUMN_SIZE, mSize);
- }
-
- static String formatTypeToMimeType(int format) {
- // TODO: Add complete list of mime types.
- switch (format) {
- case 0x3001:
- return DocumentsContract.Document.MIME_TYPE_DIR;
- case 0x3009:
- return "audio/mp3";
- case 0x3801:
- return "image/jpeg";
- default:
- return "application/octet-stream";
- }
- }
-
- static int mimeTypeToFormatType(String mimeType) {
- // TODO: Add complete list of mime types.
- switch (mimeType.toLowerCase()) {
- case Document.MIME_TYPE_DIR:
- return 0x3001;
- case "audio/mp3":
- return 0x3009;
- case "image/jpeg":
- return 0x3801;
- default:
- return 0x3000; // Undefined object.
- }
- }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index a3cf3e206a96..78ed161d47f4 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -21,11 +21,12 @@ import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Point;
+import android.mtp.MtpObjectInfo;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.util.Log;
@@ -116,37 +117,37 @@ public class MtpDocumentsProvider extends DocumentsProvider {
}
final Identifier identifier = Identifier.createFromDocumentId(documentId);
- MtpDocument document = null;
- if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+ if (identifier.mObjectHandle != CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
+ MtpObjectInfo objectInfo;
try {
- document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
+ objectInfo = mMtpManager.getObjectInfo(
+ identifier.mDeviceId, identifier.mObjectHandle);
} catch (IOException e) {
throw new FileNotFoundException(e.getMessage());
}
+ final MatrixCursor cursor = new MatrixCursor(projection);
+ CursorHelper.addToCursor(
+ objectInfo,
+ new Identifier(identifier.mDeviceId, identifier.mStorageId),
+ cursor.newRow());
+ return cursor;
} else {
MtpRoot[] roots;
try {
roots = mMtpManager.getRoots(identifier.mDeviceId);
- if (roots != null) {
- for (final MtpRoot root : roots) {
- if (identifier.mStorageId == root.mStorageId) {
- document = new MtpDocument(root);
- break;
- }
- }
- }
- if (document == null) {
- throw new FileNotFoundException();
- }
} catch (IOException e) {
throw new FileNotFoundException(e.getMessage());
}
+ for (final MtpRoot root : roots) {
+ if (identifier.mStorageId != root.mStorageId)
+ continue;
+ final MatrixCursor cursor = new MatrixCursor(projection);
+ CursorHelper.addToCursor(root, cursor.newRow());
+ return cursor;
+ }
}
- final MatrixCursor cursor = new MatrixCursor(projection);
- document.addToCursor(
- new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow());
- return cursor;
+ throw new FileNotFoundException();
}
@Override
@@ -173,6 +174,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
case "r":
return mPipeManager.readDocument(mMtpManager, identifier);
case "w":
+ // TODO: Clear the parent document loader task (if exists) and call notify
+ // when writing is completed.
return mPipeManager.writeDocument(getContext(), mMtpManager, identifier);
default:
// TODO: Add support for seekable files.
@@ -207,8 +210,10 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final int parentHandle =
mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
- notifyChildDocumentsChange(new Identifier(
- identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
+ final Identifier parentIdentifier = new Identifier(
+ identifier.mDeviceId, identifier.mStorageId, parentHandle);
+ mDocumentLoader.clearTask(parentIdentifier);
+ notifyChildDocumentsChange(parentIdentifier.toDocumentId());
} catch (IOException error) {
throw new FileNotFoundException(error.getMessage());
}
@@ -216,7 +221,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
@Override
public void onTrimMemory(int level) {
- mDocumentLoader.clearCache();
+ mDocumentLoader.clearCompletedTasks();
}
@Override
@@ -224,11 +229,19 @@ public class MtpDocumentsProvider extends DocumentsProvider {
throws FileNotFoundException {
try {
final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+ final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
+ pipe[0].close(); // 0 bytes for a new document.
final int objectHandle = mMtpManager.createDocument(
- parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
- displayName);
- final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
+ parentId.mDeviceId,
+ new MtpObjectInfo.Builder()
+ .setStorageId(parentId.mStorageId)
+ .setParent(parentId.mObjectHandle)
+ .setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
+ .setName(displayName)
+ .build(), pipe[1]);
+ final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
objectHandle).toDocumentId();
+ mDocumentLoader.clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
} catch (IOException error) {
@@ -244,7 +257,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
void closeDevice(int deviceId) throws IOException {
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearCache(deviceId);
+ mDocumentLoader.clearTasks(deviceId);
mRootScanner.scanNow();
}
@@ -253,7 +266,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
try {
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearCache(deviceId);
+ mDocumentLoader.clearTasks(deviceId);
closed = true;
} catch (IOException d) {
Log.d(TAG, "Failed to close the MTP device: " + deviceId);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 66470094579e..ca78a3e1b775 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
import android.mtp.MtpDevice;
import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
@@ -108,16 +109,12 @@ class MtpManager {
return results;
}
- synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+ synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
+ throws IOException {
final MtpDevice device = getDevice(deviceId);
return device.getObjectInfo(objectHandle);
}
- synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
- final MtpDevice device = getDevice(deviceId);
- return new MtpDocument(device.getObjectInfo(objectHandle));
- }
-
synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
@@ -142,25 +139,20 @@ class MtpManager {
}
}
- // TODO: Remove this method.
- synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
- String mimeType, String name) throws IOException {
- final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
- .setName(name)
- .setStorageId(storageId)
- .setParent(parentObjectHandle)
- .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
- .build();
- return createDocument(deviceId, objectInfo);
- }
-
- synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
+ synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo,
+ ParcelFileDescriptor source) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
- if (result == null) {
+ final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
+ if (sendObjectInfoResult == null) {
throw new IOException("Failed to create a document");
}
- return result.getObjectHandle();
+ if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
+ if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
+ sendObjectInfoResult.getCompressedSize(), source)) {
+ throw new IOException("Failed to send contents of a document");
+ }
+ }
+ return sendObjectInfoResult.getObjectHandle();
}
synchronized int getParent(int deviceId, int objectHandle) throws IOException {
@@ -178,13 +170,6 @@ class MtpManager {
device.importFile(objectHandle, target);
}
- synchronized void sendObject(int deviceId, int objectHandle, int size,
- ParcelFileDescriptor source) throws IOException {
- final MtpDevice device = getDevice(deviceId);
- if (!device.sendObject(objectHandle, size, source))
- throw new IOException("Failed to send a document");
- }
-
private MtpDevice getDevice(int deviceId) throws IOException {
final MtpDevice device = mDevices.get(deviceId);
if (device == null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 53f1b65a6f79..cd38f1e852b5 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -139,20 +139,15 @@ class PipeManager {
// Delete the target object info if it already exists (as a placeholder).
mManager.deleteDocument(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
- // Create the target object info with a correct file size.
- final int targetObjectHandle =
- mManager.createDocument(
- mIdentifier.mDeviceId,
- new MtpObjectInfo.Builder(placeholderObjectInfo)
- .setCompressedSize((int) tempFile.length())
- .build());
-
- // Upload the object.
+ // Create the target object info with a correct file size and upload the file.
+ final MtpObjectInfo targetObjectInfo =
+ new MtpObjectInfo.Builder(placeholderObjectInfo)
+ .setCompressedSize((int) tempFile.length())
+ .build();
final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
- mManager.sendObject(mIdentifier.mDeviceId,
- targetObjectHandle, (int) tempFile.length(), tempInputDescriptor);
-
+ mManager.createDocument(mIdentifier.mDeviceId,
+ targetObjectInfo, tempInputDescriptor);
} catch (IOException error) {
Log.w(MtpDocumentsProvider.TAG,
"Failed to send a file because of: " + error.getMessage());
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 1e015bdc78d5..a012d7fd49bc 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -18,6 +18,7 @@ package com.android.mtp;
import android.content.Context;
import android.database.Cursor;
+import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
@@ -31,14 +32,14 @@ import java.util.concurrent.CountDownLatch;
@SmallTest
public class DocumentLoaderTest extends AndroidTestCase {
- private BlockableTestMtpMaanger mManager;
+ private BlockableTestMtpManager mManager;
private TestContentResolver mResolver;
private DocumentLoader mLoader;
final private Identifier mParentIdentifier = new Identifier(0, 0, 0);
@Override
public void setUp() {
- mManager = new BlockableTestMtpMaanger(getContext());
+ mManager = new BlockableTestMtpManager(getContext());
mResolver = new TestContentResolver();
mLoader = new DocumentLoader(mManager, mResolver);
}
@@ -85,22 +86,17 @@ public class DocumentLoaderTest extends AndroidTestCase {
for (int i = 0; i < childDocuments.length; i++) {
final int objectHandle = i + 1;
childDocuments[i] = objectHandle;
- manager.setDocument(0, objectHandle, new MtpDocument(
- objectHandle,
- 0 /* format */,
- "file" + objectHandle,
- new Date(),
- 1024,
- 0 /* thumbnail size */,
- false /* not read only */));
+ manager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(objectHandle)
+ .build());
}
manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
}
- private static class BlockableTestMtpMaanger extends TestMtpManager {
+ private static class BlockableTestMtpManager extends TestMtpManager {
final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
- BlockableTestMtpMaanger(Context context) {
+ BlockableTestMtpManager(Context context) {
super(context);
}
@@ -113,7 +109,7 @@ public class DocumentLoaderTest extends AndroidTestCase {
}
@Override
- MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+ MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
if (latch != null) {
try {
@@ -122,7 +118,7 @@ public class DocumentLoaderTest extends AndroidTestCase {
fail();
}
}
- return super.getDocument(deviceId, objectHandle);
+ return super.getObjectInfo(deviceId, objectHandle);
}
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 1826bd077e22..9b316be48a15 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -17,9 +17,12 @@
package com.android.mtp;
import android.database.Cursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo.Builder;
+import android.mtp.MtpObjectInfo;
import android.net.Uri;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -204,14 +207,14 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument() throws IOException {
- mMtpManager.setDocument(0, 2, new MtpDocument(
- 2 /* object handle */,
- 0x3801 /* JPEG */,
- "image.jpg" /* display name */,
- new Date(1422716400000L) /* modified date */,
- 1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */,
- false /* read only */));
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(2)
+ .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
+ .setName("image.jpg")
+ .setDateModified(1422716400000L)
+ .setCompressedSize(1024 * 1024 * 5)
+ .setThumbCompressedSize(1024 * 50)
+ .build());
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -229,14 +232,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument_directory() throws IOException {
- mMtpManager.setDocument(0, 2, new MtpDocument(
- 2 /* object handle */,
- 0x3001 /* directory */,
- "directory" /* display name */,
- new Date(1422716400000L) /* modified date */,
- 0 /* file size */,
- 0 /* thumbnail size */,
- false /* read only */));
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(2)
+ .setFormat(MtpConstants.FORMAT_ASSOCIATION)
+ .setName("directory")
+ .setDateModified(1422716400000L)
+ .build());
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -278,14 +279,14 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
public void testQueryChildDocuments() throws Exception {
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
- mMtpManager.setDocument(0, 1, new MtpDocument(
- 1 /* object handle */,
- 0x3801 /* JPEG */,
- "image.jpg" /* display name */,
- new Date(0) /* modified date */,
- 1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */,
- true /* read only */));
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(1)
+ .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
+ .setName("image.jpg")
+ .setCompressedSize(1024 * 1024 * 5)
+ .setThumbCompressedSize(5 * 1024)
+ .setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY)
+ .build());
final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
assertEquals(1, cursor.getCount());
@@ -321,15 +322,10 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testDeleteDocument() throws FileNotFoundException {
- mMtpManager.setDocument(0, 1, new MtpDocument(
- 1 /* object handle */,
- 0x3801 /* JPEG */,
- "image.jpg" /* display name */,
- new Date(1422716400000L) /* modified date */,
- 1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */,
- false /* not read only */));
- mMtpManager.setParent(0, 1, 2);
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(1)
+ .setParent(2)
+ .build());
mProvider.deleteDocument("0_0_1");
assertEquals(1, mResolver.getChangeCount(
DocumentsContract.buildChildDocumentsUri(
@@ -337,7 +333,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testDeleteDocument_error() {
- mMtpManager.setParent(0, 1, 2);
+ mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(2)
+ .build());
try {
mProvider.deleteDocument("0_0_1");
fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index cfb8b044f8f4..53018cc8d810 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,6 +16,7 @@
package com.android.mtp;
+import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -56,7 +57,9 @@ public class PipeManagerTest extends AndroidTestCase {
public void testWriteDocument_basic() throws Exception {
// Create a placeholder file which should be replaced by a real file later.
- mtpManager.setDocument(0, 1, new MtpDocument(1, 0, "", new Date(), 0, 0, false));
+ mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+ .setObjectHandle(1)
+ .build());
// Upload testing bytes.
final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
@@ -69,14 +72,14 @@ public class PipeManagerTest extends AndroidTestCase {
// Check if the placeholder file is removed.
try {
- final MtpDocument placeholderDocument = mtpManager.getDocument(0, 1);
+ final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
fail(); // The placeholder file has not been deleted.
} catch (IOException e) {
// Expected error, as the file is gone.
}
// Confirm that the target file is created.
- final MtpDocument targetDocument = mtpManager.getDocument(
+ final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
assertTrue(targetDocument != null);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 94b5ba08b036..5605388db518 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -40,10 +40,9 @@ public class TestMtpManager extends MtpManager {
private final Set<Integer> mValidDevices = new HashSet<>();
private final Set<Integer> mOpenedDevices = new TreeSet<>();
private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
- private final Map<String, MtpDocument> mDocuments = new HashMap<>();
+ private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
private final Map<String, int[]> mObjectHandles = new HashMap<>();
private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
- private final Map<String, Integer> mParents = new HashMap<>();
private final Map<String, byte[]> mImportFileBytes = new HashMap<>();
TestMtpManager(Context context) {
@@ -54,16 +53,16 @@ public class TestMtpManager extends MtpManager {
mValidDevices.add(deviceId);
}
- void setObjectHandles(int deviceId, int storageId, int objectHandle, int[] documents) {
- mObjectHandles.put(pack(deviceId, storageId, objectHandle), documents);
+ void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
+ mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
}
void setRoots(int deviceId, MtpRoot[] roots) {
mRoots.put(deviceId, roots);
}
- void setDocument(int deviceId, int objectHandle, MtpDocument document) {
- mDocuments.put(pack(deviceId, objectHandle), document);
+ void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
+ mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
}
void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
@@ -78,10 +77,6 @@ public class TestMtpManager extends MtpManager {
mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
}
- void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
- mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
- }
-
@Override
void openDevice(int deviceId) throws IOException {
if (!mValidDevices.contains(deviceId) || mOpenedDevices.contains(deviceId)) {
@@ -108,25 +103,16 @@ public class TestMtpManager extends MtpManager {
}
@Override
- MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+ MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
final String key = pack(deviceId, objectHandle);
- if (mDocuments.containsKey(key)) {
- return mDocuments.get(key);
+ if (mObjectInfos.containsKey(key)) {
+ return mObjectInfos.get(key);
} else {
- throw new IOException("getDocument error: " + key);
+ throw new IOException("getObjectInfo error: " + key);
}
}
@Override
- MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
- final MtpDocument document = getDocument(deviceId, objectHandle);
- // It's impossible to set an object id of MtpObjectInfo at this stage. Also,
- // it's hard to get any information from MtpDocument, as it's designed to return them
- // only via cursors. Rework these.
- return new MtpObjectInfo.Builder().build();
- }
-
- @Override
int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle) throws IOException {
final String key = pack(deviceId, storageId, parentObjectHandle);
if (mObjectHandles.containsKey(key)) {
@@ -151,41 +137,26 @@ public class TestMtpManager extends MtpManager {
}
@Override
- int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
- // For simplicity, it allows to create only one document, and it always has the hardcoded
- // CREATED_DOCUMENT_HANDLE document handle.
- final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
- if (!mDocuments.containsKey(key)) {
- mDocuments.put(key, new MtpDocument(
- CREATED_DOCUMENT_HANDLE,
- objectInfo.getFormat(),
- objectInfo.getName(),
- new Date(objectInfo.getDateModified()),
- objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize(),
- false /* Always writable for testing. */));
- } else {
- throw new IOException();
- }
- return CREATED_DOCUMENT_HANDLE;
- }
-
- @Override
- void sendObject(int deviceId, int objectHandle, int size, ParcelFileDescriptor source)
+ int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
throws IOException {
- final String key = pack(deviceId, objectHandle);
- if (!mDocuments.containsKey(key)) {
+ final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
+ if (mObjectInfos.containsKey(key)) {
throw new IOException();
}
-
- ParcelFileDescriptor.AutoCloseInputStream inputStream =
- new ParcelFileDescriptor.AutoCloseInputStream(source);
- byte[] buffer = new byte[size];
- if (inputStream.read(buffer, 0, size) != size) {
- throw new IOException();
+ mObjectInfos.put(key, objectInfo);
+ if (objectInfo.getFormat() != 0x3001) {
+ try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
+ new ParcelFileDescriptor.AutoCloseInputStream(source)) {
+ final byte[] buffer = new byte[objectInfo.getCompressedSize()];
+ if (inputStream.read(buffer, 0, objectInfo.getCompressedSize()) !=
+ objectInfo.getCompressedSize()) {
+ throw new IOException();
+ }
+
+ mImportFileBytes.put(pack(deviceId, CREATED_DOCUMENT_HANDLE), buffer);
+ }
}
-
- mImportFileBytes.put(pack(deviceId, objectHandle), buffer);
+ return CREATED_DOCUMENT_HANDLE;
}
@Override
@@ -201,18 +172,18 @@ public class TestMtpManager extends MtpManager {
@Override
void deleteDocument(int deviceId, int objectHandle) throws IOException {
final String key = pack(deviceId, objectHandle);
- if (mDocuments.containsKey(key)) {
- mDocuments.remove(key);
+ if (mObjectInfos.containsKey(key)) {
+ mObjectInfos.remove(key);
} else {
throw new IOException();
}
}
@Override
- synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+ int getParent(int deviceId, int objectHandle) throws IOException {
final String key = pack(deviceId, objectHandle);
- if (mParents.containsKey(key)) {
- return mParents.get(key);
+ if (mObjectInfos.containsKey(key)) {
+ return mObjectInfos.get(key).getParent();
} else {
throw new IOException();
}
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9294a16ca6b5..1473f24bae42 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Program is nie op jou toestel geïnstalleer nie"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Wys horlosiesekondes"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Gebruik verdeling in Kitsinstellings"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 13f768d87953..7ab6af9cb72d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"መተግበሪያ በእርስዎ መሣሪያ ላይ አልተጫነም"</string>
<string name="clock_seconds" msgid="7689554147579179507">"የሰዓት ሰከንዶችን አሳይ"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"በፈጣን ቅንብሮች ውስጥ ምልክት መጥሪያን ይጠቀሙ"</string>
+ <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6889a4352983..bd026501dc45 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -439,4 +439,8 @@
<string name="activity_not_found" msgid="348423244327799974">"التطبيق غير مثبّت على جهازك"</string>
<string name="clock_seconds" msgid="7689554147579179507">"عرض ثواني الساعة"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"استخدام ترقيم الصفحات في الإعدادات السريعة"</string>
+ <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 51513bd5ebf8..a0d7d2b21c7c 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Tətbiq cihazınızda quraşdırılmayıb"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Saatın saniyəsini göstərin"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Sürətli Ayarlarda səhifə nömrələməsindən istifadə edin"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 014d802204ec..a14d0fc70c07 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Приложението не е инсталирано на устройството ви"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Показване на секундите на часовника"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Използване на разделянето на страници от бързите настройки"</string>
+ <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 08600193fc1c..e819d54e0901 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"আপনার ডিভাইসে অ্যাপ্লিকেশান ইনস্টল করা নেই"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ঘড়ির সেকেন্ড দেখায়"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"দ্রুত সেটিংসে পেজিং ব্যবহার করুন"</string>
+ <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 9c32052992cd..7def415f9bdb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Torna a ordenar la Configuració ràpida"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a la Configuració ràpida"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utilitza la paginació a la Configuració ràpida"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4d96a011a094..a73947fdfb05 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -439,4 +439,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikace není v zařízení nainstalována."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Zobrazit sekundovou ručičku"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Použít v Rychlém nastavení stránkování"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 7f005a383d3b..6f491874e6a8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Applikationen er ikke installeret på din enhed."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Vis sekunder"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Brug sidelayout i Hurtige indstillinger"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 36f3c985672e..a659077bd821 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Die App ist nicht auf Ihrem Gerät installiert."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Uhrsekunden anzeigen"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Seitenlayout in den Schnelleinstellungen verwenden"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8e73b21d5d9c..bcfc4589a6b8 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Η εφαρμογή δεν έχει εγκατασταθεί στη συσκευή σας"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Εμφάνιση δευτερολέπτων ρολογιού"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Χρήση τηλεειδοποίησης στις Γρήγορες ρυθμίσεις"</string>
+ <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0b499557f8fd..fb781d4d91ea 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0b499557f8fd..fb781d4d91ea 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0b499557f8fd..fb781d4d91ea 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c4dca9c491dc..10834a23baa7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en el dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Usar la paginación en la Configuración rápida"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e316a944793c..37c81f4936c0 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utilizar paginación en Ajustes rápidos"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index a151bce0f475..f4218a3a6eb3 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Rakendust pole teie seadmesse installitud"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Kella sekundite kuvamine"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Kasuta kiirseadetes lehe paigutust"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 37cdee70163d..fbf0eb42e73c 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikazioa ez dago gailuan instalatuta"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Erakutsi erlojuko segundoak"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Erakutsi ezarpen bizkorren distira"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Erabili ezarpen bizkorretako orriak pasatzeko diseinu berria"</string>
+ <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 80d09185003d..fa01c47df918 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"برنامه در دستگاه شما نصب نیست"</string>
<string name="clock_seconds" msgid="7689554147579179507">"نمایش ثانیه‌های ساعت"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"استفاده از صفحه‌بندی در تنظیمات سریع"</string>
+ <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index b86247acf597..6c4a0299069b 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Sovellusta ei ole asennettu laitteellesi."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Näytä sekunnit kellossa"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Käytä sivutusta pika-asetuksissa"</string>
+ <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f99447cde722..07a2fc349f5e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Afficher les secondes sur l\'horloge"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utiliser la pagination dans les paramètres rapides"</string>
+ <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index aada1eb83f7a..0aa45ae8a393 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Afficher les secondes sur l\'horloge"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utiliser mise en page dans fenêtre de configuration rapide"</string>
+ <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 951809fe1d8c..ec64f229ea4e 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"A aplicación non está instalada no teu dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do reloxo"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utilizar paxinación en Configuración rápida"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 02e4e5209892..e873c95f14f7 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"તમારા ઉપકરણ પર એપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ઘડિયાળ સેકન્ડ બતાવો"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ઝડપી સેટિંગ્સમાં પૃષ્ઠાંકનનો ઉપયોગ કરો"</string>
+ <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3ed090c90111..83ac46eaf42d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"ऐप्लिकेशन आपके डिवाइस पर इंस्टॉल नहीं है"</string>
<string name="clock_seconds" msgid="7689554147579179507">"घड़ी के सेकंड दिखाएं"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"त्वरित सेटिंग में पेजिंग का उपयोग करें"</string>
+ <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9698abac2dc5..b5d993117334 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -436,4 +436,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikacija nije instalirana na vašem uređaju"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Prikaži sekunde na satu"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Upotrijebi redni broj stranice u Brzim postavkama"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 37cb0a81610f..79390a69990e 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Az alkalmazás nincs telepítve eszközén."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Másodpercek megjelenítése az órán"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Oldalelrendezés használata a gyorsbeállításokban"</string>
+ <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index e31cf497199a..9f48b2618e3e 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Հավելվածը տեղադրված չէ սարքի վրա"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Ցույց տալ ժամացույցի վայրկյանները"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Օգտագործել էջերի դասավորությունը Արագ կարգավորումներում"</string>
+ <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ad8141bb2b34..600241151aab 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikasi tidak dipasang di perangkat"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Tampilkan detik jam"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Gunakan pembagian laman di Setelan Cepat"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 02caf17e496c..e8e053090fda 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Forritið er ekki uppsett í tækinu."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Sýna sekúndur á klukku"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Nota síðuskoðun í flýtistillingum"</string>
+ <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ab5d8beab1f9..8ee5f078a806 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Applicazione non installata sul dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostra i secondi nell\'orologio"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utilizza nuovo layout in Impostazioni rapide"</string>
+ <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9dad8aaf464f..e38501d5afb3 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -437,4 +437,12 @@
<string name="activity_not_found" msgid="348423244327799974">"האפליקציה אינה מותקנת במכשיר"</string>
<string name="clock_seconds" msgid="7689554147579179507">"הצג שניות בשעון"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
+ <!-- no translation found for qs_rearrange (8060918697551068765) -->
+ <skip />
+ <!-- no translation found for show_brightness (6613930842805942519) -->
+ <skip />
+ <!-- no translation found for qs_paging (7020133150248666132) -->
+ <skip />
+ <!-- no translation found for experimental (6198182315536726162) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9cb2fc856263..a73f4c1d9fc6 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"アプリが端末にインストールされていません"</string>
<string name="clock_seconds" msgid="7689554147579179507">"時計の秒を表示"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"クイック設定でページ設定を使用する"</string>
+ <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index a9728b25a6bd..f1035a8d8fc5 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"აპლიკაცია თქვენს მოწყობილობაზე დაყენებული არ არის"</string>
<string name="clock_seconds" msgid="7689554147579179507">"საათის წამების ჩვენება"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"გამოიყენეთ გვერდების დანომვრა სწრაფ პარამეტრებში"</string>
+ <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 1d61372522aa..8b82e5fce6c9 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Қолданба құрылғыда орнатылмаған"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Сағат секундтарын көрсету"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Жылдам параметрлерде беттерді нөмірлеуді пайдалану"</string>
+ <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index c233f83e2af7..b8db00f9067c 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"កម្មវិធីមិនបានដំឡើងនៅលើឧបករណ៍របស់អ្នកទេ"</string>
<string name="clock_seconds" msgid="7689554147579179507">"បង្ហាញវិនាទី"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ប្រើការចុះទំព័រនៅក្នុងការកំណត់រហ័ស"</string>
+ <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index d486e56a7266..316c04fe12a2 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ಗಡಿಯಾರದ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪುಟಗಳನ್ನು ಬಳಸಿ"</string>
+ <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 35057544cf8a..d7f1543a87d0 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"기기에 애플리케이션이 설치되어 있지 않습니다."</string>
<string name="clock_seconds" msgid="7689554147579179507">"시계 초 단위 표시"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"빠른 설정에서 페이지 레이아웃 사용"</string>
+ <string name="experimental" msgid="6198182315536726162">"베타"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 968a65a76e5e..efe699b5519c 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Колдонмо сиздин түзмөгүңүздө орнотулган эмес"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Сааттын секунддары көрсөтүлсүн"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарыктыгын көрсөтүү"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Ыкчам жөндөөлөрдөн баракты номерлөөнү колдонуу"</string>
+ <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index f34c70eefbd4..50b4522caabf 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ບໍ່​ຖືກ​ຕິດ​ຕັ້ງ​ຢູ່​ໃນ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ໃຊ້​ການ​ໃສ່​ໜ້າ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
+ <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index cf70d6bd5a31..90827785d109 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Programa neįdiegta įrenginyje"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Rodyti laikrodžio sekundes"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Naudoti puslapių kaitą sparčiuosiuose nustatymuose"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5e2db80b9927..5fb4bb0c2f86 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -436,4 +436,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Lietojumprogramma nav instalēta jūsu ierīcē."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Rādīt pulksteņa sekundes"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Izmantot lapošanu ātrajos iestatījumos"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index fe781b6b3219..8571b3f441f1 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Апликацијата не е инсталирана на уредот"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Прикажи ги секундите на часовникот"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Користете прелистување страници во Брзи поставки"</string>
+ <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 6e6fc55e0214..4b11962a91c4 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"നിങ്ങളുടെ ഉപകരണത്തിൽ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുക"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ദ്രുത്ര ക്രമീകരണത്തിൽ പേജിംഗ് ഉപയോഗിക്കുക"</string>
+ <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 65250bbbec60..d1dbd6dbf2d4 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -433,4 +433,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Апп-ыг таны төхөөрөмжид суулгаагүй байна"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Цагийн секундыг харуулах"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Хуудаслалтыг түргэн тохиргоонд ашиглаарай"</string>
+ <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 0f71b4bc446b..fe50f909bd1a 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"अनुप्रयोग आपल्या डिव्हाइसवर स्थापित केलेला नाही"</string>
<string name="clock_seconds" msgid="7689554147579179507">"घड्‍याळ सेकंद दर्शवा"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"दृत सेटिंग्जची पुनर्रचना करा"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"दृत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"द्रुत सेटिंग्जमध्ये लिखाण वापरा"</string>
+ <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 596275c6e058..01f7edfd6066 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikasi tidak dipasang pada peranti anda"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Tunjukkan saat jam"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Gunakan penghalaman dalam Tetapan Pantas"</string>
+ <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 3147d0cc73f3..d0eaccfaf550 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"အပလီကေးရှင်းကို သင်၏ ကိရိယာထဲသို့ တပ်ဆင်မပေးရသေးပါ။"</string>
<string name="clock_seconds" msgid="7689554147579179507">"နာရီ စက္ကန့်များကို ပြရန်"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"အမြန် ဆက်တင်များထဲတွင် စာမျက်နှာ ပုံစံချမှုကို အသုံးပြုပါ"</string>
+ <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index f1bfbe1d8a98..e582039142db 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Appen er ikke installert på enheten din"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Vis sekunder på klokken"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Bruk sidetall i hurtiginnstillingene"</string>
+ <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 461a15f83173..c3dc703e72ad 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"तपाईँको यन्त्रमा अनुप्रयोग स्थापना भएको छैन"</string>
<string name="clock_seconds" msgid="7689554147579179507">"घडीमा सेकेन्ड देखाउनुहोस्"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"द्रुत सेटिङहरूमा पेजिंग प्रयोग गर्नुहोस्"</string>
+ <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index b74f91da327b..13f02d59fae0 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Deze app is niet geïnstalleerd op uw apparaat"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Klokseconden weergeven"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Paginering gebruiken in Snelle instellingen"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 06746ccf08b2..ef3d2f3585bd 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"ਐਪਲੀਕੇਸ਼ਨ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਪੇਜਿੰਗ ਵਰਤੋ"</string>
+ <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 66100c19045e..8c2c5c430213 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikacja nie jest zainstalowana na urządzeniu"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Pokaż sekundy na zegarku"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Użyj stronicowania w Szybkich ustawieniach"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 53cea01a3ce5..3803b812013d 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"O app não está instalado no seu dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Usar paginação nas \"Configurações rápidas\""</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 50064137ac98..be42e8a72d53 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"A aplicação não está instalada no dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Definições rápidas"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Utilizar paginação nas Definições rápidas"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 53cea01a3ce5..3803b812013d 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"O app não está instalado no seu dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Usar paginação nas \"Configurações rápidas\""</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d97e16b820aa..bb8f2c3fe6b5 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -436,4 +436,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplicația nu este instalată pe dispozitiv"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Afișează secundele pe ceas"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Folosiți paginarea în Setările rapide"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d67ad389b4c2..9609f40bdff8 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -269,7 +269,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нет сети"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Не удалось найти доступные сети Wi-Fi"</string>
- <string name="quick_settings_cast_title" msgid="7709016546426454729">"Wi-Fi-монитор"</string>
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляция"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Передача изображения"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Безымянное устройство"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово к передаче"</string>
@@ -439,4 +439,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Приложение не установлено на вашем устройстве"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Показывать секунды"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Разбить Быстрые настройки на страницы"</string>
+ <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 06cb62644399..9e7883422230 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"යෙදුම ඔබේ උපාංගය මත ස්ථාපනය කර නැත"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ඔරලෝසු තත්පර පෙන්වන්න"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ඉක්මන් සැකසීම්වල පිටු පිරිසැලසුම් භාවිත කරන්න"</string>
+ <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 037074bab323..e3f0fb32c964 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -439,4 +439,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikácia nie je nainštalovaná na zariadení"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Zobraziť sekundy"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Použite stránkovanie v Rýchlych nastaveniach"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 31fe5d88027f..4dffcfa2bcd1 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikacija ni nameščena v napravi"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Prikaz sekund pri uri"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Uporaba postavitve strani v hitrih nastavitvah"</string>
+ <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index ffb8bea66147..20c342638aaa 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Aplikacioni nuk është instaluar në pajisjen tënde."</string>
<string name="clock_seconds" msgid="7689554147579179507">"Trego sekondat e orës"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Përdor faqosjen te Cilësimet e shpejta"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index bae0284761c9..1dcde3a1b0bb 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -436,4 +436,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Апликација није инсталирана на уређају"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Приказуј секунде на сату"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Користи листање страница у Брзим подешавањима"</string>
+ <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 6588f10a0135..0abeb1eb4d85 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Appen är inte installerad på enheten"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Visa klocksekunder"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Använd sidindelning i snabbinställningarna"</string>
+ <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 623f12cac3d4..d000004c530a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Programu haijasakinishwa kwenye kifaa chako"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Onyesha sekunde za saa"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Tumia nambari za ukurasa katika Mipangilio ya Haraka"</string>
+ <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index c6cb337e7d4d..7b1ded375bac 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"சாதனத்தில் பயன்பாடு நிறுவப்படவில்லை"</string>
<string name="clock_seconds" msgid="7689554147579179507">"கடிகார வினாடிகளைக் காட்டு"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"விரைவு அமைப்புகளில் புதிய பக்கத் தளவமைப்பைப் பயன்படுத்து"</string>
+ <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c0717c1fd90c..06762bd7ef4e 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"అనువర్తనం మీ పరికరంలో ఇన్‌స్టాల్ చేయలేదు"</string>
<string name="clock_seconds" msgid="7689554147579179507">"గడియారం సెకన్లు చూపు"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"శీఘ్ర సెట్టింగ్‌ల్లో పేజింగ్‌ను ఉపయోగించు"</string>
+ <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e16fdd2cccae..52c7af7f2f27 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"ยังไม่ได้ติดตั้งแอปพลิเคชันบนอุปกรณ์ของคุณ"</string>
<string name="clock_seconds" msgid="7689554147579179507">"แสดงวินาทีของนาฬิกา"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"ใช้การแบ่งหน้าในการตั้งค่าด่วน"</string>
+ <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d970084ca02f..66056d10dc64 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Hindi naka-install ang application sa iyong device"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Ipakita ang mga segundo ng orasan"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Gamitin ang paging sa Mga Mabilisang Setting"</string>
+ <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index b22b4fbc7eb8..fdad0d554a54 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Uygulama, cihazınızda yüklü değil"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Saatin saniyelerini göster"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Hızlı Ayarlar\'da sayfa ayırmayı kullan"</string>
+ <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 898611d38c87..9dde80178d2d 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Додаток не встановлено на вашому пристрої"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Показувати секунди на годиннику"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Показувати швидкі налаштування у вигляді сторінок"</string>
+ <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index d5683e1daecc..a4ef16acae62 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"ایپلیکیشن آپ کے آلہ پر انسٹال نہیں ہے"</string>
<string name="clock_seconds" msgid="7689554147579179507">"گھڑی کے سیکنڈز دکھائیں"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"فوری ترتیبات میں پیجنگ استعمال کریں"</string>
+ <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index e31af6b44342..118c4b8a6968 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Ilova qurilmangizga o‘rnatilmagan"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Soat soniyalari ko‘rsatilsin"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Tezkor sozlamalarda peyjingdan foydalanish"</string>
+ <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 030bbbe7ec70..460d57ae4410 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Ứng dụng chưa được cài đặt trên thiết bị của bạn"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Hiển thị giây đồng hồ"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Sử dụng đánh số trang trong Cài đặt nhanh"</string>
+ <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b046415bac2c..05644e70be6e 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -437,4 +437,12 @@
<string name="activity_not_found" msgid="348423244327799974">"您的设备中未安装此应用"</string>
<string name="clock_seconds" msgid="7689554147579179507">"显示时钟的秒数"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
+ <!-- no translation found for qs_rearrange (8060918697551068765) -->
+ <skip />
+ <!-- no translation found for show_brightness (6613930842805942519) -->
+ <skip />
+ <!-- no translation found for qs_paging (7020133150248666132) -->
+ <skip />
+ <!-- no translation found for experimental (6198182315536726162) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index d568dba45d2d..f7cac90e1522 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"尚未在裝置安裝應用程式"</string>
<string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"在快速設定使用分頁"</string>
+ <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 702ad53449e4..369172f36836 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -437,4 +437,8 @@
<string name="activity_not_found" msgid="348423244327799974">"您的裝置未安裝這個應用程式"</string>
<string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"在快速設定中使用分頁功能"</string>
+ <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8774036f4749..2a14a9f2b6d4 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -435,4 +435,8 @@
<string name="activity_not_found" msgid="348423244327799974">"Uhlelo lokusebenza alufakiwe kudivayisi yakho"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Bonisa amasekhondi wewashi"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
+ <string name="qs_paging" msgid="7020133150248666132">"Sebenzisa i-paging kuzilungiselelo ezisheshayo"</string>
+ <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
</resources>
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 d30411a2c52e..f4439bfacea4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -262,14 +262,21 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
}
+ /**
+ * Resolves the intent to launch the camera application.
+ */
+ public ResolveInfo resolveCameraIntent() {
+ return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ KeyguardUpdateMonitor.getCurrentUser());
+ }
+
private void updateCameraVisibility() {
if (mCameraImageView == null) {
// Things are not set up yet; reply hazy, ask again later
return;
}
- ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
- PackageManager.MATCH_DEFAULT_ONLY,
- KeyguardUpdateMonitor.getCurrentUser());
+ ResolveInfo resolved = resolveCameraIntent();
boolean visible = !isCameraDisabledByDpm() && resolved != null
&& getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
&& mUserSetupComplete;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 93ecb06f693d..d0a7f8aa95c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,10 +166,13 @@ public class LockIcon extends KeyguardAffordanceView {
if (mAccessibilityController == null) {
return;
}
+ boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
+ || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
+
boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
- boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+ boolean clickToForceLock = trustManagedOrFingerprintAllowed
&& !mAccessibilityController.isAccessibilityEnabled();
- boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+ boolean longClickToForceLock = trustManagedOrFingerprintAllowed
&& !clickToForceLock;
setClickable(clickToForceLock || clickToUnlock);
setLongClickable(longClickToForceLock);
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 3ad72468fe59..814a65e522da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,7 +21,10 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -62,6 +65,8 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
+import java.util.List;
+
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -2462,7 +2467,28 @@ public class NotificationPanelView extends PanelView implements
getCenterIcon().setLaunchingAffordance(launchingAffordance);
}
- public boolean canCameraGestureBeLaunched() {
- return !mAfforanceHelper.isSwipingInProgress();
+ /**
+ * Whether the camera application can be launched for the camera launch gesture.
+ *
+ * @param keyguardIsShowing whether keyguard is being shown
+ */
+ public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+ ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
+ String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
+ ? null : resolveInfo.activityInfo.packageName;
+ return packageToLaunch != null &&
+ (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
+ !mAfforanceHelper.isSwipingInProgress();
+ }
+
+ /**
+ * Return true if the applications with the package name is running in foreground.
+ *
+ * @param pkgName application package name.
+ */
+ private boolean isForegroundApp(String pkgName) {
+ ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+ return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
}
}
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 7b04da029b06..ab1b59799f42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4150,7 +4150,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void onCameraLaunchGestureDetected() {
- if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+ if (!mNotificationPanel.canCameraGestureBeLaunched(
+ mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
return;
}
if (!mDeviceInteractive) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 95a8d391c8eb..6475cbf158cb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -421,8 +421,9 @@ public class VolumeDialog {
}
}
} else {
- final boolean vmute = row.ss.level == 0;
- mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0);
+ final boolean vmute = row.ss.level == row.ss.levelMin;
+ mController.setStreamVolume(stream,
+ vmute ? row.lastAudibleLevel : row.ss.levelMin);
}
row.userAttempt = 0; // reset the grace period, slider should update immediately
}
@@ -1024,6 +1025,7 @@ public class VolumeDialog {
final int minProgress = mRow.ss.levelMin * 100;
if (progress < minProgress) {
seekBar.setProgress(minProgress);
+ progress = minProgress;
}
}
final int userLevel = getImpliedLevel(seekBar, progress);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4288fa2668dc..882899e4fe96 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -177,7 +177,7 @@ class AlarmManagerService extends SystemService {
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
- private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index fda6479e2d56..92e6814c42d1 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.content.Context;
+import android.os.Trace;
import android.util.Slog;
import java.lang.reflect.Constructor;
@@ -75,43 +76,48 @@ public class SystemServiceManager {
*/
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
- final String name = serviceClass.getName();
- Slog.i(TAG, "Starting " + name);
-
- // Create the service.
- if (!SystemService.class.isAssignableFrom(serviceClass)) {
- throw new RuntimeException("Failed to create " + name
- + ": service must extend " + SystemService.class.getName());
- }
- final T service;
try {
- Constructor<T> constructor = serviceClass.getConstructor(Context.class);
- service = constructor.newInstance(mContext);
- } catch (InstantiationException ex) {
- throw new RuntimeException("Failed to create service " + name
- + ": service could not be instantiated", ex);
- } catch (IllegalAccessException ex) {
- throw new RuntimeException("Failed to create service " + name
- + ": service must have a public constructor with a Context argument", ex);
- } catch (NoSuchMethodException ex) {
- throw new RuntimeException("Failed to create service " + name
- + ": service must have a public constructor with a Context argument", ex);
- } catch (InvocationTargetException ex) {
- throw new RuntimeException("Failed to create service " + name
- + ": service constructor threw an exception", ex);
- }
+ final String name = serviceClass.getName();
+ Slog.i(TAG, "Starting " + name);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
+
+ // Create the service.
+ if (!SystemService.class.isAssignableFrom(serviceClass)) {
+ throw new RuntimeException("Failed to create " + name
+ + ": service must extend " + SystemService.class.getName());
+ }
+ final T service;
+ try {
+ Constructor<T> constructor = serviceClass.getConstructor(Context.class);
+ service = constructor.newInstance(mContext);
+ } catch (InstantiationException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service could not be instantiated", ex);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (InvocationTargetException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service constructor threw an exception", ex);
+ }
- // Register it.
- mServices.add(service);
+ // Register it.
+ mServices.add(service);
- // Start it.
- try {
- service.onStart();
- } catch (RuntimeException ex) {
- throw new RuntimeException("Failed to start service " + name
- + ": onStart threw an exception", ex);
+ // Start it.
+ try {
+ service.onStart();
+ } catch (RuntimeException ex) {
+ throw new RuntimeException("Failed to start service " + name
+ + ": onStart threw an exception", ex);
+ }
+ return service;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
- return service;
}
/**
@@ -127,18 +133,22 @@ public class SystemServiceManager {
mCurrentPhase = phase;
Slog.i(TAG, "Starting phase " + mCurrentPhase);
-
- final int serviceLen = mServices.size();
- for (int i = 0; i < serviceLen; i++) {
- final SystemService service = mServices.get(i);
- try {
- service.onBootPhase(mCurrentPhase);
- } catch (Exception ex) {
- throw new RuntimeException("Failed to boot service "
- + service.getClass().getName()
- + ": onBootPhase threw an exception during phase "
- + mCurrentPhase, ex);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "OnBootPhase " + phase);
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onBootPhase(mCurrentPhase);
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to boot service "
+ + service.getClass().getName()
+ + ": onBootPhase threw an exception during phase "
+ + mCurrentPhase, ex);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4aef23b267d7..09ac7d913c9e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -215,6 +215,7 @@ import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UpdateLock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -1885,7 +1886,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
case FINISH_BOOTING_MSG: {
if (msg.arg1 != 0) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
finishBooting();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
if (msg.arg2 != 0) {
enableScreenAfterBoot();
@@ -6450,7 +6453,9 @@ public final class ActivityManagerService extends ActivityManagerNative
mBootAnimationComplete = true;
}
if (callFinishBooting) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
finishBooting();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -6465,7 +6470,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (booting) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
finishBooting();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
if (enableScreen) {
@@ -17411,8 +17418,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Can't call out of the system process with a lock held, so post a message.
- mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
- app.instrumentationUiAutomationConnection).sendToTarget();
+ if (app.instrumentationUiAutomationConnection != null) {
+ mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+ app.instrumentationUiAutomationConnection).sendToTarget();
+ }
app.instrumentationWatcher = null;
app.instrumentationUiAutomationConnection = null;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f50df3a1f34f..37ddd4df7ffb 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3975,8 +3975,7 @@ final class ActivityStack {
* for whatever reason. Ensures the HistoryRecord is updated with the
* correct configuration and all other bookkeeping is handled.
*/
- final boolean ensureActivityConfigurationLocked(ActivityRecord r,
- int globalChanges) {
+ final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges) {
if (mConfigWillChange) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check (will change): " + r);
@@ -4589,25 +4588,19 @@ final class ActivityStack {
void addConfigOverride(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.getLaunchBounds();
- final Configuration config =
- mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
- r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
- r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
- bounds);
- if (config != null) {
- task.updateOverrideConfiguration(config, bounds);
- }
+ final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+ mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+ r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
+ r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
+ bounds, config);
r.taskConfigOverride = task.mOverrideConfig;
}
private void setAppTask(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.getLaunchBounds();
- final Configuration config =
- mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
- if (config != null) {
- task.updateOverrideConfiguration(config, bounds);
- }
+ final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+ mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds(), config);
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c86056b1a5f0..33e0ef83299c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@ import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
-import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -334,6 +333,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
// temp. rect used during resize calculation so we don't need to create a new object each time.
private final Rect tempRect = new Rect();
+ private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
+ private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -2917,19 +2919,19 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityRecord r = stack.topRunningActivityLocked(null);
final boolean resizeTasks = r != null && r.task.mResizeable;
- final IntArray changedTaskIds = new IntArray(stack.numTasks());
- final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
- stack.mFullscreen = mWindowManager.resizeStack(
- stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
- for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
- final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
- if (task == null) {
- Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
- continue;
+ mTmpBounds.clear();
+ mTmpConfigs.clear();
+ if (resizeTasks) {
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ TaskRecord task = tasks.get(i);
+ task.updateOverrideConfiguration(stackId, bounds);
+ mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+ mTmpBounds.put(task.taskId, task.mBounds);
}
- task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
}
-
+ stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs,
+ mTmpBounds);
if (stack.mStackId == DOCKED_STACK_ID) {
// Dock stack funness...Yay!
if (stack.mFullscreen) {
@@ -3024,25 +3026,27 @@ public final class ActivityStackSupervisor implements DisplayListener {
stackId = FREEFORM_WORKSPACE_STACK_ID;
}
if (stackId != task.stack.mStackId) {
- final String reason = "resizeTask";
- final ActivityStack stack =
- moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+ moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
}
- final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
- if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
+ final Configuration overrideConfig = task.updateOverrideConfiguration(stackId, bounds);
+ // This variable holds information whether the configuration didn't change in a signficant
+ // way and the activity was kept the way it was. If it's false, it means the activity had
+ // to be relaunched due to configuration change.
+ boolean kept = true;
+ if (overrideConfig != null) {
ActivityRecord r = task.topRunningActivityLocked(null);
if (r != null) {
final ActivityStack stack = task.stack;
- final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
+ kept = stack.ensureActivityConfigurationLocked(r, 0);
+ // All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0);
- if (!updated) {
+ if (!kept) {
resumeTopActivitiesLocked(stack, null, null);
}
}
}
+ mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept);
}
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 5c4fd138c19c..735c06ffbcf2 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -234,7 +235,7 @@ class LaunchingTaskPositioner {
break;
}
}
- task.setInitialBounds(proposal);
+ task.updateOverrideConfiguration(FREEFORM_WORKSPACE_STACK_ID, proposal);
}
private boolean shiftedToFar(Rect start, int shiftPolicy) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9cbaec53ce60..12c7b863e1e3 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -52,6 +53,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.XmlUtils;
@@ -63,6 +65,7 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Objects;
final class TaskRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -106,6 +109,13 @@ final class TaskRecord {
static final int INVALID_TASK_ID = -1;
+ // The height/width divide used when fitting a task within a bounds with method
+ // {@link #fitWithinBounds}.
+ // We always want the task to to be visible in the bounds without affecting its size when
+ // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+ // the input bounds right or bottom side minus the width or height divided by this value.
+ private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
final int taskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
@@ -218,6 +228,8 @@ final class TaskRecord {
Configuration mOverrideConfig = Configuration.EMPTY;
+ private Rect mTmpRect = new Rect();
+
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
mService = service;
@@ -271,8 +283,7 @@ final class TaskRecord {
long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
- int callingUid, String callingPackage, boolean resizeable, boolean privileged,
- Rect bounds) {
+ int callingUid, String callingPackage, boolean resizeable, boolean privileged) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -309,7 +320,6 @@ final class TaskRecord {
mCallingPackage = callingPackage;
mResizeable = resizeable;
mPrivileged = privileged;
- mBounds = mLastNonFullscreenBounds = bounds;
}
void touchActiveTime() {
@@ -1163,7 +1173,8 @@ final class TaskRecord {
autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
- callingUid, callingPackage, resizeable, privileged, bounds);
+ callingUid, callingPackage, resizeable, privileged);
+ task.updateOverrideConfiguration(INVALID_STACK_ID, bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
activities.get(activityNdx).task = task;
@@ -1173,25 +1184,51 @@ final class TaskRecord {
return task;
}
- boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
+ /**
+ * Update task's override configuration based on the bounds.
+ * @return Update configuration or null if there is no change.
+ */
+ Configuration updateOverrideConfiguration(int stackId, Rect bounds) {
+ if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+ // For freeform stack we don't adjust the size of the tasks to match that of the
+ // stack, but we do try to make sure the tasks are still contained with the
+ // bounds of the stack.
+ bounds = fitWithinBounds(bounds);
+ }
+ if (Objects.equals(mBounds, bounds)) {
+ return null;
+ }
Configuration oldConfig = mOverrideConfig;
- mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
- // We override the configuration only when the task's dimensions are different from the
- // display. In this manner, we know that if the override configuration is empty, the task
- // is necessarily fullscreen.
- mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+
+ mFullscreen = bounds == null;
if (mFullscreen) {
if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
mLastNonFullscreenBounds = mBounds;
}
mBounds = null;
+ mOverrideConfig = Configuration.EMPTY;
} else {
mBounds = new Rect(bounds);
if (stack.mStackId != DOCKED_STACK_ID) {
mLastNonFullscreenBounds = mBounds;
}
- }
- return !mOverrideConfig.equals(oldConfig);
+
+ final Configuration serviceConfig = mService.mConfiguration;
+ mOverrideConfig = new Configuration(serviceConfig);
+ // TODO(multidisplay): Update Dp to that of display stack is on.
+ final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ mOverrideConfig.screenWidthDp =
+ Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
+ mOverrideConfig.screenHeightDp =
+ Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
+ mOverrideConfig.smallestScreenWidthDp =
+ Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+ mOverrideConfig.orientation =
+ (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+ ? Configuration.ORIENTATION_PORTRAIT
+ : Configuration.ORIENTATION_LANDSCAPE;
+ }
+ return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
/** Returns the stack that should be used to launch this task. */
@@ -1225,12 +1262,39 @@ final class TaskRecord {
return mLastNonFullscreenBounds;
}
- void setInitialBounds(Rect rect) {
- if (mBounds == null) {
- mBounds = new Rect();
+ /** Fits the tasks within the input bounds adjusting the task bounds as needed.
+ * @param bounds Bounds to fit the task within. Nothing is done if null.
+ * @return Returns final configuration after updating with the adjusted bounds.
+ * */
+ Rect fitWithinBounds(Rect bounds) {
+ if (bounds == null || mBounds == null || bounds.contains(mBounds)) {
+ return bounds;
+ }
+ mTmpRect.set(mBounds);
+
+ if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
+ final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+ int horizontalDiff = bounds.left - mBounds.left;
+ if ((horizontalDiff < 0 && mBounds.left >= maxRight)
+ || (mBounds.left + horizontalDiff >= maxRight)) {
+ horizontalDiff = maxRight - mBounds.left;
+ }
+ mTmpRect.left += horizontalDiff;
+ mTmpRect.right += horizontalDiff;
}
- mBounds.set(rect);
- mLastNonFullscreenBounds = mBounds;
+
+ if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
+ final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+ int verticalDiff = bounds.top - mBounds.top;
+ if ((verticalDiff < 0 && mBounds.top >= maxBottom)
+ || (mBounds.top + verticalDiff >= maxBottom)) {
+ verticalDiff = maxBottom - mBounds.top;
+ }
+ mTmpRect.top += verticalDiff;
+ mTmpRect.bottom += verticalDiff;
+ }
+
+ return mTmpRect;
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7e46db8dd4e7..cbb3c39e514c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -24,7 +24,9 @@ import android.app.IUserSwitchObserver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.os.Binder;
+import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -51,7 +53,6 @@ import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintDaemonCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.view.Display;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
@@ -60,6 +61,7 @@ import static android.Manifest.permission.USE_FINGERPRINT;
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -83,6 +85,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
private ClientMonitor mAuthClient = null;
private ClientMonitor mEnrollClient = null;
private ClientMonitor mRemoveClient = null;
+ private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
+ new ArrayList<>();
private final AppOpsManager mAppOps;
private static final long MS_PER_SEC = 1000;
@@ -259,6 +263,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
// If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
// may still be in the queue; remove it.
mHandler.removeCallbacks(mLockoutReset);
+ notifyLockoutResetMonitors();
}
private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
@@ -499,6 +504,23 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
opPackageName) == AppOpsManager.MODE_ALLOWED;
}
+ private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
+ if (!mLockoutMonitors.contains(monitor)) {
+ mLockoutMonitors.add(monitor);
+ }
+ }
+
+ private void removeLockoutResetCallback(
+ FingerprintServiceLockoutResetMonitor monitor) {
+ mLockoutMonitors.remove(monitor);
+ }
+
+ private void notifyLockoutResetMonitors() {
+ for (int i = 0; i < mLockoutMonitors.size(); i++) {
+ mLockoutMonitors.get(i).sendLockoutReset();
+ }
+ }
+
private class ClientMonitor implements IBinder.DeathRecipient {
IBinder token;
IFingerprintServiceReceiver receiver;
@@ -614,7 +636,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
FingerprintUtils.vibrateFingerprintSuccess(getContext());
}
result |= true; // we have a valid fingerprint
- mLockoutReset.run();
+ mHandler.post(mLockoutReset);
}
return result;
}
@@ -654,6 +676,36 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
}
+ private class FingerprintServiceLockoutResetMonitor {
+
+ private final IFingerprintServiceLockoutResetCallback mCallback;
+
+ public FingerprintServiceLockoutResetMonitor(
+ IFingerprintServiceLockoutResetCallback callback) {
+ mCallback = callback;
+ }
+
+ public void sendLockoutReset() {
+ if (mCallback != null) {
+ try {
+ mCallback.onLockoutReset(mHalDeviceId);
+ } catch (DeadObjectException e) {
+ Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
+ mHandler.post(mRemoveCallbackRunnable);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+ }
+ }
+ }
+
+ private final Runnable mRemoveCallbackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
+ }
+ };
+ }
+
private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
@Override
@@ -922,7 +974,19 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
public void resetTimeout(byte [] token) {
checkPermission(RESET_FINGERPRINT_LOCKOUT);
// TODO: confirm security token when we move timeout management into the HAL layer.
- mLockoutReset.run();
+ mHandler.post(mLockoutReset);
+ }
+
+ @Override
+ public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
+ throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ addLockoutResetMonitor(
+ new FingerprintServiceLockoutResetMonitor(callback));
+ }
+ });
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 0a12d5a78d66..cbe61c3da5af 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -46,7 +46,6 @@ import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
-import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -149,6 +148,7 @@ public class ZenModeHelper {
mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
}
mHandler.postMetricsTimer();
+ evaluateZenMode("onSystemReady", true);
}
public void onUserSwitched(int user) {
@@ -330,13 +330,14 @@ public class ZenModeHelper {
}
mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
mConfigs.put(config.user, config);
- if (config.equals(mConfig)) return true;
if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
ZenLog.traceConfig(reason, mConfig, config);
final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
getNotificationPolicy(config));
mConfig = config;
- dispatchOnConfigChanged();
+ if (config.equals(mConfig)) {
+ dispatchOnConfigChanged();
+ }
if (policyChanged){
dispatchOnPolicyChanged();
}
@@ -370,9 +371,7 @@ public class ZenModeHelper {
private boolean evaluateZenMode(String reason, boolean setRingerMode) {
if (DEBUG) Log.d(TAG, "evaluateZenMode");
- final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>();
- final int zen = computeZenMode(automaticRules);
- if (zen == mZenMode) return false;
+ final int zen = computeZenMode();
ZenLog.traceSetZenMode(zen, reason);
mZenMode = zen;
updateRingerModeAffectedStreams();
@@ -381,7 +380,9 @@ public class ZenModeHelper {
applyZenToRingerMode();
}
applyRestrictions();
- mHandler.postDispatchOnZenModeChanged();
+ if (zen != mZenMode) {
+ mHandler.postDispatchOnZenModeChanged();
+ }
return true;
}
@@ -391,7 +392,7 @@ public class ZenModeHelper {
}
}
- private int computeZenMode(ArraySet<ZenRule> automaticRulesOut) {
+ private int computeZenMode() {
if (mConfig == null) return Global.ZEN_MODE_OFF;
if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c75a1d306a87..66170d453260 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -136,9 +136,6 @@ public final class SELinuxMMAC {
case "signer":
policies.add(readSignerOrThrow(parser));
break;
- case "default":
- policies.add(readDefaultOrThrow(parser));
- break;
default:
skip(parser);
}
@@ -233,45 +230,6 @@ public final class SELinuxMMAC {
}
/**
- * Loop over a default element looking for seinfo child tags. A {@link Policy}
- * instance will be created and returned in the process. All other tags encountered
- * will be skipped.
- *
- * @param parser an XmlPullParser object representing a default element.
- * @return the constructed {@link Policy} instance
- * @throws IOException
- * @throws XmlPullParserException
- * @throws IllegalArgumentException if any of the validation checks fail while
- * parsing tag values.
- * @throws IllegalStateException if any of the invariants fail when constructing
- * the {@link Policy} instance.
- */
- private static Policy readDefaultOrThrow(XmlPullParser parser) throws IOException,
- XmlPullParserException {
-
- parser.require(XmlPullParser.START_TAG, null, "default");
- Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
- pb.setAsDefaultPolicy();
-
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
-
- String tagName = parser.getName();
- if ("seinfo".equals(tagName)) {
- String seinfo = parser.getAttributeValue(null, "value");
- pb.setGlobalSeinfoOrThrow(seinfo);
- readSeinfo(parser);
- } else {
- skip(parser);
- }
- }
-
- return pb.build();
- }
-
- /**
* Loop over a package element looking for seinfo child tags. If found return the
* value attribute of the seinfo tag, otherwise return null. All other tags encountered
* will be skipped.
@@ -337,35 +295,28 @@ public final class SELinuxMMAC {
/**
* Applies a security label to a package based on an seinfo tag taken from a matched
- * policy. All signature based policy stanzas are consulted first and, if no match
- * is found, the default policy stanza is then consulted. The security label is
- * attached to the ApplicationInfo instance of the package in the event that a matching
- * policy was found.
+ * policy. All signature based policy stanzas are consulted and, if no match is
+ * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
+ * used. The security label is attached to the ApplicationInfo instance of the package
+ * in the event that a matching policy was found.
*
* @param pkg object representing the package to be labeled.
- * @return boolean which determines whether a non null seinfo label was assigned
- * to the package. A null value simply represents that no policy matched.
*/
- public static boolean assignSeinfoValue(PackageParser.Package pkg) {
+ public static void assignSeinfoValue(PackageParser.Package pkg) {
synchronized (sPolicies) {
for (Policy policy : sPolicies) {
String seinfo = policy.getMatchedSeinfo(pkg);
if (seinfo != null) {
pkg.applicationInfo.seinfo = seinfo;
- if (DEBUG_POLICY_INSTALL) {
- Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
- "seinfo=" + seinfo);
- }
- return true;
+ break;
}
}
}
if (DEBUG_POLICY_INSTALL) {
- Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
- "seinfo will remain null");
+ Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
+ "seinfo=" + pkg.applicationInfo.seinfo);
}
- return false;
}
/**
@@ -506,30 +457,16 @@ public final class SELinuxMMAC {
* .build();
* }
* </pre>
- * <p>
- * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
- * default based Policy instance.
- * </p>
- * <pre>
- * {@code
- * Policy policy = new Policy.PolicyBuilder()
- * .setAsDefaultPolicy()
- * .setGlobalSeinfoOrThrow("default")
- * .build();
- * }
- * </pre>
*/
final class Policy {
private final String mSeinfo;
- private final boolean mDefaultStanza;
private final Set<Signature> mCerts;
private final Map<String, String> mPkgMap;
// Use the PolicyBuilder pattern to instantiate
private Policy(PolicyBuilder builder) {
mSeinfo = builder.mSeinfo;
- mDefaultStanza = builder.mDefaultStanza;
mCerts = Collections.unmodifiableSet(builder.mCerts);
mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
}
@@ -545,15 +482,6 @@ final class Policy {
}
/**
- * Return whether this policy object represents a default stanza.
- *
- * @return A boolean indicating if this object represents a default policy stanza.
- */
- public boolean isDefaultStanza() {
- return mDefaultStanza;
- }
-
- /**
* Return whether this policy object contains package name mapping refinements.
*
* @return A boolean indicating if this object has inner package name mappings.
@@ -584,10 +512,6 @@ final class Policy {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- if (mDefaultStanza) {
- sb.append("defaultStanza=true ");
- }
-
for (Signature cert : mCerts) {
sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
}
@@ -609,22 +533,15 @@ final class Policy {
* is determined using the following steps:
* </p>
* <ul>
- * <li> If this Policy instance is defined as a default stanza:
- * <ul><li>Return the global seinfo value</li></ul>
+ * <li> All certs used to sign the apk and all certs stored with this policy
+ * instance are tested for set equality. If this fails then null is returned.
+ * </li>
+ * <li> If all certs match then an appropriate inner package stanza is
+ * searched based on package name alone. If matched, the stored seinfo
+ * value for that mapping is returned.
* </li>
- * <li> If this Policy instance is defined as a signer stanza:
- * <ul>
- * <li> All certs used to sign the apk and all certs stored with this policy
- * instance are tested for set equality. If this fails then null is returned.
- * </li>
- * <li> If all certs match then an appropriate inner package stanza is
- * searched based on package name alone. If matched, the stored seinfo
- * value for that mapping is returned.
- * </li>
- * <li> If all certs matched and no inner package stanza matches then return
- * the global seinfo value. The returned value can be null in this case.
- * </li>
- * </ul>
+ * <li> If all certs matched and no inner package stanza matches then return
+ * the global seinfo value. The returned value can be null in this case.
* </li>
* </ul>
* <p>
@@ -636,37 +553,34 @@ final class Policy {
* A value of null can also be returned if no match occured.
*/
public String getMatchedSeinfo(PackageParser.Package pkg) {
- if (!mDefaultStanza) {
- // Check for exact signature matches across all certs.
- Signature[] certs = mCerts.toArray(new Signature[0]);
- if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
- return null;
- }
+ // Check for exact signature matches across all certs.
+ Signature[] certs = mCerts.toArray(new Signature[0]);
+ if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+ return null;
+ }
- // Check for inner package name matches given that the
- // signature checks already passed.
- String seinfoValue = mPkgMap.get(pkg.packageName);
- if (seinfoValue != null) {
- return seinfoValue;
- }
+ // Check for inner package name matches given that the
+ // signature checks already passed.
+ String seinfoValue = mPkgMap.get(pkg.packageName);
+ if (seinfoValue != null) {
+ return seinfoValue;
}
- // Return the global seinfo value (even if it's null).
+ // Return the global seinfo value.
return mSeinfo;
}
/**
* A nested builder class to create {@link Policy} instances. A {@link Policy}
* class instance represents one valid policy stanza found in a mac_permissions.xml
- * file. A valid policy stanza is defined to be either a signer or default stanza
- * which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
- * {@link #build} method ensures a set of invariants are upheld enforcing the correct
- * stanza structure before returning a valid Policy object.
+ * file. A valid policy stanza is defined to be a signer stanza which obeys the rules
+ * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+ * ensures a set of invariants are upheld enforcing the correct stanza structure
+ * before returning a valid Policy object.
*/
public static final class PolicyBuilder {
private String mSeinfo;
- private boolean mDefaultStanza;
private final Set<Signature> mCerts;
private final Map<String, String> mPkgMap;
@@ -676,19 +590,6 @@ final class Policy {
}
/**
- * Sets this stanza as a default stanza. All policy stanzas are assumed to
- * be signer stanzas unless this method is explicitly called. Default stanzas
- * are treated differently with respect to allowable child tags, ordering and
- * when and how policy decisions are enforced.
- *
- * @return The reference to this PolicyBuilder.
- */
- public PolicyBuilder setAsDefaultPolicy() {
- mDefaultStanza = true;
- return this;
- }
-
- /**
* Adds a signature to the set of certs used for validation checks. The purpose
* being that all contained certs will need to be matched against all certs
* contained with an apk.
@@ -710,11 +611,8 @@ final class Policy {
/**
* Set the global seinfo tag for this policy stanza. The global seinfo tag
- * represents the seinfo element that is used in one of two ways depending on
- * its context. When attached to a signer tag the global seinfo represents an
- * assignment when there isn't a further inner package refinement in policy.
- * When used with a default tag, it represents the only allowable assignment
- * value.
+ * when attached to a signer tag represents the assignment when there isn't a
+ * further inner package refinement in policy.
*
* @param seinfo the seinfo value given as a String.
* @return The reference to this PolicyBuilder.
@@ -740,9 +638,7 @@ final class Policy {
/**
* Create a package name to seinfo value mapping. Each mapping represents
* the seinfo value that will be assigned to the described package name.
- * These localized mappings allow the global seinfo to be overriden. This
- * mapping provides no value when used in conjunction with a default stanza;
- * enforced through the {@link #build} method.
+ * These localized mappings allow the global seinfo to be overriden.
*
* @param pkgName the android package name given to the app
* @param seinfo the seinfo value that will be assigned to the passed pkgName
@@ -799,51 +695,25 @@ final class Policy {
* about the expected structure of a policy stanza.
* Those invariants are:
* </p>
- * <ul>
- * <li> If a default stanza
- * <ul>
- * <li> an attached global seinfo tag must be present </li>
- * <li> no signatures and no package names can be present </li>
- * </ul>
- * </li>
- * <li> If a signer stanza
- * <ul>
- * <li> at least one cert must be found </li>
- * <li> either a global seinfo value is present OR at least one
- * inner package mapping must be present BUT not both. </li>
- * </ul>
- * </li>
- * </ul>
- *
+ * <ul>
+ * <li> at least one cert must be found </li>
+ * <li> either a global seinfo value is present OR at least one
+ * inner package mapping must be present BUT not both. </li>
+ * </ul>
* @return an instance of {@link Policy} with the options set from this builder
* @throws IllegalStateException if an invariant is violated.
*/
public Policy build() {
Policy p = new Policy(this);
- if (p.mDefaultStanza) {
- if (p.mSeinfo == null) {
- String err = "Missing global seinfo tag with default stanza.";
- throw new IllegalStateException(err);
- }
- if (p.mCerts.size() != 0) {
- String err = "Certs not allowed with default stanza.";
- throw new IllegalStateException(err);
- }
- if (!p.mPkgMap.isEmpty()) {
- String err = "Inner package mappings not allowed with default stanza.";
- throw new IllegalStateException(err);
- }
- } else {
- if (p.mCerts.size() == 0) {
- String err = "Missing certs with signer tag. Expecting at least one.";
- throw new IllegalStateException(err);
- }
- if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
- String err = "Only seinfo tag XOR package tags are allowed within " +
- "a signer stanza.";
- throw new IllegalStateException(err);
- }
+ if (p.mCerts.isEmpty()) {
+ String err = "Missing certs with signer tag. Expecting at least one.";
+ throw new IllegalStateException(err);
+ }
+ if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+ String err = "Only seinfo tag XOR package tags are allowed within " +
+ "a signer stanza.";
+ throw new IllegalStateException(err);
}
return p;
@@ -858,7 +728,6 @@ final class Policy {
* <ul>
* <li> signer stanzas with inner package mappings </li>
* <li> signer stanzas with global seinfo tags </li>
- * <li> default stanza </li>
* </ul>
* This comparison also checks for duplicate entries on the input selectors. Any
* found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
@@ -875,11 +744,6 @@ final class PolicyComparator implements Comparator<Policy> {
@Override
public int compare(Policy p1, Policy p2) {
- // Give precedence to signature stanzas over default stanzas
- if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
- return p1.isDefaultStanza() ? 1 : -1;
- }
-
// Give precedence to stanzas with inner package mappings
if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
return p1.hasInnerPackages() ? -1 : 1;
@@ -887,7 +751,7 @@ final class PolicyComparator implements Comparator<Policy> {
// Check for duplicate entries
if (p1.getSignatures().equals(p2.getSignatures())) {
- // Checks if default stanza or a signer w/o inner package names
+ // Checks if signer w/o inner package names
if (p1.hasGlobalSeinfo()) {
duplicateFound = true;
Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9ddbccadc658..48e205f22864 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4462,7 +4462,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mAppsToBeHidden.isEmpty()) {
if (dismissKeyguard && !mKeyguardSecure) {
mAppsThatDismissKeyguard.add(appToken);
- } else if (win.isDrawnLw()) {
+ } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
mWinShowWhenLocked = win;
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
@@ -4496,7 +4496,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWinDismissingKeyguard = win;
mSecureDismissingKeyguard = mKeyguardSecure;
mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
- } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) {
+ } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
+ && (win.isDrawnLw() || win.hasAppShownWindows())) {
if (DEBUG_LAYOUT) Slog.v(TAG,
"Setting mHideLockScreen to true by win " + win);
mHideLockScreen = true;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 554af2849919..666d902682a7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,7 +23,6 @@ import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -41,13 +40,6 @@ class Task implements DimLayer.DimLayerUser {
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
- // The amount we divide the height/width of the bounds we are trying to fit the task within
- // when using the method {@link #fitWithinBounds}.
- // We always want the task to to be visible in the bounds without affecting its size when
- // fitting. To make sure this is the case, we don't adjust the task left or top side pass
- // the input bounds right or bottom side minus the width or height divided by this value.
- private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
-
TaskStack mStack;
final AppTokenList mAppTokens = new AppTokenList();
final int mTaskId;
@@ -84,13 +76,13 @@ class Task implements DimLayer.DimLayerUser {
// of creating a new object per fullscreen task on a display.
private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
- Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
+ Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+ Configuration config) {
mTaskId = taskId;
mStack = stack;
mUserId = userId;
mService = service;
- mOverrideConfig = Configuration.EMPTY;
- setBounds(bounds);
+ setBounds(bounds, config);
}
DisplayContent getDisplayContent() {
@@ -172,43 +164,18 @@ class Task implements DimLayer.DimLayerUser {
}
}
- /** Fits the tasks within the input bounds adjusting the task bounds as needed.
- * @param bounds Bounds to fit the task within. Nothing is done if null.
- * @return Returns true if the task bounds was adjusted in any way.
- * */
- boolean fitWithinBounds(Rect bounds) {
- if (bounds == null || bounds.contains(mBounds)) {
- return false;
+ /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
+ boolean setBounds(Rect bounds, Configuration config) {
+ if (config == null) {
+ config = Configuration.EMPTY;
}
- mTmpRect2.set(mBounds);
-
- if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
- final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
- int horizontalDiff = bounds.left - mBounds.left;
- if ((horizontalDiff < 0 && mBounds.left >= maxRight)
- || (mBounds.left + horizontalDiff >= maxRight)) {
- horizontalDiff = maxRight - mBounds.left;
- }
- mTmpRect2.left += horizontalDiff;
- mTmpRect2.right += horizontalDiff;
+ if (bounds == null && !Configuration.EMPTY.equals(config)) {
+ throw new IllegalArgumentException("null bounds but non empty configuration: "
+ + config);
}
-
- if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
- final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
- int verticalDiff = bounds.top - mBounds.top;
- if ((verticalDiff < 0 && mBounds.top >= maxBottom)
- || (mBounds.top + verticalDiff >= maxBottom)) {
- verticalDiff = maxBottom - mBounds.top;
- }
- mTmpRect2.top += verticalDiff;
- mTmpRect2.bottom += verticalDiff;
+ if (bounds != null && Configuration.EMPTY.equals(config)) {
+ throw new IllegalArgumentException("non null bounds, but empty configuration");
}
-
- return setBounds(mTmpRect2);
- }
-
- /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
- boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
final DisplayContent displayContent = mStack.getDisplayContent();
@@ -241,7 +208,7 @@ class Task implements DimLayer.DimLayerUser {
mBounds.set(bounds);
mRotation = rotation;
updateDimLayer();
- updateOverrideConfiguration();
+ mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
return true;
}
@@ -249,36 +216,12 @@ class Task implements DimLayer.DimLayerUser {
out.set(mBounds);
}
- private void updateOverrideConfiguration() {
- final Configuration serviceConfig = mService.mCurConfiguration;
- if (mFullscreen) {
- mOverrideConfig = Configuration.EMPTY;
- return;
- }
-
- if (mOverrideConfig == Configuration.EMPTY) {
- mOverrideConfig = new Configuration();
- }
-
- // TODO(multidisplay): Update Dp to that of display stack is on.
- final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
- mOverrideConfig.screenWidthDp =
- Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
- mOverrideConfig.screenHeightDp =
- Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
- mOverrideConfig.smallestScreenWidthDp =
- Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
- mOverrideConfig.orientation =
- (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
- ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
- }
-
void updateDisplayInfo(final DisplayContent displayContent) {
if (displayContent == null) {
return;
}
if (mFullscreen) {
- setBounds(null);
+ setBounds(null, Configuration.EMPTY);
return;
}
final int newRotation = displayContent.getDisplayInfo().rotation;
@@ -313,7 +256,7 @@ class Task implements DimLayer.DimLayerUser {
mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
break;
}
- setBounds(mTmpRect2);
+ setBounds(mTmpRect2, mOverrideConfig);
}
/** Updates the dim layer bounds, recreating it if needed. */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 25a71d9fc7f1..a7ef2f8ae165 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -27,6 +27,7 @@ import android.os.RemoteException;
import android.util.EventLog;
import android.util.IntArray;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.DisplayInfo;
import com.android.server.EventLogTags;
@@ -96,15 +97,15 @@ public class TaskStack implements DimLayer.DimLayerUser {
/**
* Set the bounds of the stack and its containing tasks.
- * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
* @param resizeTasks If true, the tasks within the stack will also be resized.
- * @param changedTaskIds Output list of Ids of tasks that changed in bounds.
- * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+ * @param configs Configuration for individual tasks, keyed by task id.
+ * @param taskBounds Bounds for individual tasks, keyed by task id.
* @return True if the stack bounds was changed.
* */
- boolean setBounds(Rect bounds, boolean resizeTasks, IntArray changedTaskIds,
- List<Configuration> newTaskConfigs) {
- if (!setBounds(bounds)) {
+ boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs,
+ SparseArray<Rect> taskBounds) {
+ if (!setBounds(stackBounds)) {
return false;
}
@@ -113,20 +114,17 @@ public class TaskStack implements DimLayer.DimLayerUser {
}
// Update bounds of containing tasks.
- final Rect newBounds = mFullscreen ? null : mBounds;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = mTasks.get(taskNdx);
- if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- // For freeform stack we don't adjust the size of the tasks to match that of the
- // stack, but we do try to make sure the tasks are still contained with the
- // bounds of the stack.
- if (task.fitWithinBounds(newBounds)) {
- changedTaskIds.add(task.mTaskId);
- newTaskConfigs.add(task.mOverrideConfig);
+ Configuration config = configs.get(task.mTaskId);
+ if (config != null) {
+ Rect bounds = taskBounds.get(task.mTaskId);
+ if (bounds == null) {
+ bounds = stackBounds;
}
- } else if (task.setBounds(newBounds)) {
- changedTaskIds.add(task.mTaskId);
- newTaskConfigs.add(task.mOverrideConfig);
+ task.setBounds(bounds, config);
+ } else {
+ Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?");
}
}
return true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf690a56c2d1..bf7d1e7f27ee 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3041,8 +3041,8 @@ public class WindowManagerService extends IWindowManager.Stub
Binder.restoreCallingIdentity(origId);
}
- private Task createTaskLocked(
- int taskId, int stackId, int userId, AppWindowToken atoken, Rect bounds) {
+ private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
+ Rect bounds, Configuration config) {
if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
+ " atoken=" + atoken + " bounds=" + bounds);
final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3050,17 +3050,17 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
}
EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
- Task task = new Task(taskId, stack, userId, this, bounds);
+ Task task = new Task(taskId, stack, userId, this, bounds, config);
mTaskIdToTask.put(taskId, task);
stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
return task;
}
@Override
- public Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+ public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds) {
+ Rect taskBounds, Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3084,7 +3084,7 @@ public class WindowManagerService extends IWindowManager.Stub
AppWindowToken atoken = findAppWindowToken(token.asBinder());
if (atoken != null) {
Slog.w(TAG, "Attempted to add existing app token: " + token);
- return null;
+ return;
}
atoken = new AppWindowToken(this, token, voiceInteraction);
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
@@ -3098,10 +3098,8 @@ public class WindowManagerService extends IWindowManager.Stub
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
Task task = mTaskIdToTask.get(taskId);
- Configuration outConfig = null;
if (task == null) {
- task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds);
- outConfig = task.mOverrideConfig;
+ task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
}
task.addAppToken(addPos, atoken);
@@ -3110,13 +3108,11 @@ public class WindowManagerService extends IWindowManager.Stub
// Application tokens start out hidden.
atoken.hidden = true;
atoken.hiddenRequested = true;
-
- return outConfig;
}
}
@Override
- public Configuration setAppTask(IBinder token, int taskId, Rect taskBounds) {
+ public void setAppTask(IBinder token, int taskId, Rect taskBounds, Configuration config) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppTask()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3126,20 +3122,18 @@ public class WindowManagerService extends IWindowManager.Stub
final AppWindowToken atoken = findAppWindowToken(token);
if (atoken == null) {
Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
- return null;
+ return;
}
final Task oldTask = atoken.mTask;
oldTask.removeAppToken(atoken);
Task newTask = mTaskIdToTask.get(taskId);
- Configuration outConfig = null;
if (newTask == null) {
newTask = createTaskLocked(
- taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds);
- outConfig = newTask.mOverrideConfig;
+ taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds,
+ config);
}
newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
- return outConfig;
}
}
@@ -4599,19 +4593,19 @@ public class WindowManagerService extends IWindowManager.Stub
* @param stackId Id of stack to resize.
* @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
* @param resizeTasks If true, the tasks within the stack will also be resized.
- * @param changedTaskIds Output list of Ids of tasks that changed in bounds due to resize.
- * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+ * @param configs Configurations for tasks in the resized stack, keyed by task id.
+ * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
* @return True if the stack is now fullscreen.
* */
public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
- IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+ SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ " not found.");
}
- if (stack.setBounds(bounds, resizeTasks, changedTaskIds, newTaskConfigs)) {
+ if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -4648,19 +4642,20 @@ public class WindowManagerService extends IWindowManager.Stub
* Returns a {@link Configuration} object that contains configurations settings
* that should be overridden due to the operation.
*/
- public Configuration resizeTask(int taskId, Rect bounds) {
+ public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
throw new IllegalArgumentException("resizeTask: taskId " + taskId
+ " not found.");
}
- if (task.setBounds(bounds)) {
+ if (task.setBounds(bounds, configuration)) {
task.resizeWindows();
- task.getDisplayContent().layoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
+ if (relayout) {
+ task.getDisplayContent().layoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
}
- return new Configuration(task.mOverrideConfig);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 21dd647b6785..aafaf8373cf8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,6 +38,7 @@ import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.IMountService;
import android.util.DisplayMetrics;
@@ -175,97 +176,103 @@ public final class SystemServer {
}
private void run() {
- // If a device's clock is before 1970 (before 0), a lot of
- // APIs crash dealing with negative numbers, notably
- // java.io.File#setLastModified, so instead we fake it and
- // hope that time from cell towers or NTP fixes it shortly.
- if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
- Slog.w(TAG, "System clock is before 1970; setting to 1970.");
- SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
- }
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
+ // If a device's clock is before 1970 (before 0), a lot of
+ // APIs crash dealing with negative numbers, notably
+ // java.io.File#setLastModified, so instead we fake it and
+ // hope that time from cell towers or NTP fixes it shortly.
+ if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
+ Slog.w(TAG, "System clock is before 1970; setting to 1970.");
+ SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
+ }
- // If the system has "persist.sys.language" and friends set, replace them with
- // "persist.sys.locale". Note that the default locale at this point is calculated
- // using the "-Duser.locale" command line flag. That flag is usually populated by
- // AndroidRuntime using the same set of system properties, but only the system_server
- // and system apps are allowed to set them.
- //
- // NOTE: Most changes made here will need an equivalent change to
- // core/jni/AndroidRuntime.cpp
- if (!SystemProperties.get("persist.sys.language").isEmpty()) {
- final String languageTag = Locale.getDefault().toLanguageTag();
-
- SystemProperties.set("persist.sys.locale", languageTag);
- SystemProperties.set("persist.sys.language", "");
- SystemProperties.set("persist.sys.country", "");
- SystemProperties.set("persist.sys.localevar", "");
- }
+ // If the system has "persist.sys.language" and friends set, replace them with
+ // "persist.sys.locale". Note that the default locale at this point is calculated
+ // using the "-Duser.locale" command line flag. That flag is usually populated by
+ // AndroidRuntime using the same set of system properties, but only the system_server
+ // and system apps are allowed to set them.
+ //
+ // NOTE: Most changes made here will need an equivalent change to
+ // core/jni/AndroidRuntime.cpp
+ if (!SystemProperties.get("persist.sys.language").isEmpty()) {
+ final String languageTag = Locale.getDefault().toLanguageTag();
+
+ SystemProperties.set("persist.sys.locale", languageTag);
+ SystemProperties.set("persist.sys.language", "");
+ SystemProperties.set("persist.sys.country", "");
+ SystemProperties.set("persist.sys.localevar", "");
+ }
- // Here we go!
- Slog.i(TAG, "Entered the Android system server!");
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
-
- // In case the runtime switched since last boot (such as when
- // the old runtime was removed in an OTA), set the system
- // property so that it is in sync. We can't do this in
- // libnativehelper's JniInvocation::Init code where we already
- // had to fallback to a different runtime because it is
- // running as root and we need to be the system user to set
- // the property. http://b/11463182
- SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
-
- // Enable the sampling profiler.
- if (SamplingProfilerIntegration.isEnabled()) {
- SamplingProfilerIntegration.start();
- mProfilerSnapshotTimer = new Timer();
- mProfilerSnapshotTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- SamplingProfilerIntegration.writeSnapshot("system_server", null);
- }
- }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
- }
+ // Here we go!
+ Slog.i(TAG, "Entered the Android system server!");
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
+
+ // In case the runtime switched since last boot (such as when
+ // the old runtime was removed in an OTA), set the system
+ // property so that it is in sync. We can't do this in
+ // libnativehelper's JniInvocation::Init code where we already
+ // had to fallback to a different runtime because it is
+ // running as root and we need to be the system user to set
+ // the property. http://b/11463182
+ SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
+
+ // Enable the sampling profiler.
+ if (SamplingProfilerIntegration.isEnabled()) {
+ SamplingProfilerIntegration.start();
+ mProfilerSnapshotTimer = new Timer();
+ mProfilerSnapshotTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ SamplingProfilerIntegration.writeSnapshot("system_server", null);
+ }
+ }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
+ }
- // Mmmmmm... more memory!
- VMRuntime.getRuntime().clearGrowthLimit();
+ // Mmmmmm... more memory!
+ VMRuntime.getRuntime().clearGrowthLimit();
- // The system server has to run all of the time, so it needs to be
- // as efficient as possible with its memory usage.
- VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
+ // The system server has to run all of the time, so it needs to be
+ // as efficient as possible with its memory usage.
+ VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
- // Some devices rely on runtime fingerprint generation, so make sure
- // we've defined it before booting further.
- Build.ensureFingerprintProperty();
+ // Some devices rely on runtime fingerprint generation, so make sure
+ // we've defined it before booting further.
+ Build.ensureFingerprintProperty();
- // Within the system server, it is an error to access Environment paths without
- // explicitly specifying a user.
- Environment.setUserRequired(true);
+ // Within the system server, it is an error to access Environment paths without
+ // explicitly specifying a user.
+ Environment.setUserRequired(true);
- // Ensure binder calls into the system always run at foreground priority.
- BinderInternal.disableBackgroundScheduling(true);
+ // Ensure binder calls into the system always run at foreground priority.
+ BinderInternal.disableBackgroundScheduling(true);
- // Prepare the main looper thread (this thread).
- android.os.Process.setThreadPriority(
+ // Prepare the main looper thread (this thread).
+ android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
- android.os.Process.setCanSelfBackground(false);
- Looper.prepareMainLooper();
+ android.os.Process.setCanSelfBackground(false);
+ Looper.prepareMainLooper();
- // Initialize native services.
- System.loadLibrary("android_servers");
+ // Initialize native services.
+ System.loadLibrary("android_servers");
- // Check whether we failed to shut down last time we tried.
- // This call may not return.
- performPendingShutdown();
+ // Check whether we failed to shut down last time we tried.
+ // This call may not return.
+ performPendingShutdown();
- // Initialize the system context.
- createSystemContext();
+ // Initialize the system context.
+ createSystemContext();
- // Create the system service manager.
- mSystemServiceManager = new SystemServiceManager(mSystemContext);
- LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
+ // Create the system service manager.
+ mSystemServiceManager = new SystemServiceManager(mSystemContext);
+ LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
// Start services.
try {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
@@ -273,6 +280,8 @@ public final class SystemServer {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
// For debug builds, log event loop stalls to dropbox for analysis.
@@ -340,7 +349,9 @@ public final class SystemServer {
// Now that the power manager has been started, let the activity manager
// initialize power management features.
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitPowerManagement");
mActivityManagerService.initPowerManagement();
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
// Manages LEDs and display backlight so we need it to bring up the display.
mSystemServiceManager.startService(LightsService.class);
@@ -363,14 +374,16 @@ public final class SystemServer {
}
// Start the package manager.
- Slog.i(TAG, "Package Manager");
+ traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "User Service");
+ traceBeginAndSlog("StartUserManagerService");
ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
// Initialize attribute cache used to cache resources from packages.
AttributeCache.init(mSystemContext);
@@ -442,17 +455,20 @@ public final class SystemServer {
Slog.i(TAG, "Reading configuration...");
SystemConfig.getInstance();
- Slog.i(TAG, "Scheduling Policy");
+ traceBeginAndSlog("StartSchedulingPolicyService");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mSystemServiceManager.startService(TelecomLoaderService.class);
- Slog.i(TAG, "Telephony Registry");
+ traceBeginAndSlog("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "Entropy Mixer");
+ traceBeginAndSlog("StartEntropyMixer");
entropyMixer = new EntropyMixer(context);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mContentResolver = context.getContentResolver();
@@ -460,47 +476,55 @@ public final class SystemServer {
mSystemServiceManager.startService(CameraService.class);
// The AccountManager must come before the ContentService
+ traceBeginAndSlog("StartAccountManagerService");
try {
// TODO: seems like this should be disable-able, but req'd by ContentService
- Slog.i(TAG, "Account Manager");
accountManager = new AccountManagerService(context);
ServiceManager.addService(Context.ACCOUNT_SERVICE, accountManager);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Account Manager", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "Content Manager");
+ traceBeginAndSlog("StartContentService");
contentService = ContentService.main(context,
mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "System Content Providers");
+ traceBeginAndSlog("InstallSystemProviders");
mActivityManagerService.installSystemProviders();
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "Vibrator Service");
+ traceBeginAndSlog("StartVibratorService");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "Consumer IR Service");
+ traceBeginAndSlog("StartConsumerIrService");
consumerIr = new ConsumerIrService(context);
ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mSystemServiceManager.startService(AlarmManagerService.class);
alarm = IAlarmManager.Stub.asInterface(
ServiceManager.getService(Context.ALARM_SERVICE));
- Slog.i(TAG, "Init Watchdog");
+ traceBeginAndSlog("InitWatchdog");
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "Input Manager");
+ traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "Window Manager");
+ traceBeginAndSlog("StartWindowManagerService");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mActivityManagerService.setWindowManager(wm);
@@ -523,7 +547,6 @@ public final class SystemServer {
} else if (disableBluetooth) {
Slog.i(TAG, "Bluetooth Service disabled by config");
} else {
- Slog.i(TAG, "Bluetooth Service");
mSystemServiceManager.startService(BluetoothService.class);
}
} catch (RuntimeException e) {
@@ -544,21 +567,23 @@ public final class SystemServer {
// Bring up services needed for UI.
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+ traceBeginAndSlog("StartInputMethodManagerService");
try {
- Slog.i(TAG, "Input Method Service");
imm = new InputMethodManagerService(context);
ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
} catch (Throwable e) {
reportWtf("starting Input Manager Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartAccessibilityManagerService");
try {
- Slog.i(TAG, "Accessibility Manager");
ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
new AccessibilityManagerService(context));
} catch (Throwable e) {
reportWtf("starting Accessibility Manager", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
try {
@@ -588,11 +613,13 @@ public final class SystemServer {
// as appropriate.
mSystemServiceManager.startService(UiModeManagerService.class);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformBootDexOpt");
try {
mPackageManagerService.performBootDexOpt();
} catch (Throwable e) {
reportWtf("performing boot dexopt", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
try {
ActivityManagerNative.getDefault().showBootMessage(
@@ -604,13 +631,14 @@ public final class SystemServer {
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartLockSettingsService");
try {
- Slog.i(TAG, "LockSettingsService");
lockSettings = new LockSettingsService(context);
ServiceManager.addService("lock_settings", lockSettings);
} catch (Throwable e) {
reportWtf("starting LockSettingsService service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (!SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
mSystemServiceManager.startService(PersistentDataBlockService.class);
@@ -624,64 +652,70 @@ public final class SystemServer {
}
if (!disableSystemUI) {
+ traceBeginAndSlog("StartStatusBarManagerService");
try {
- Slog.i(TAG, "Status Bar");
statusBar = new StatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartClipboardService");
try {
- Slog.i(TAG, "Clipboard Service");
ServiceManager.addService(Context.CLIPBOARD_SERVICE,
new ClipboardService(context));
} catch (Throwable e) {
reportWtf("starting Clipboard Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNetwork) {
+ traceBeginAndSlog("StartNetworkManagementService");
try {
- Slog.i(TAG, "NetworkManagement Service");
networkManagement = NetworkManagementService.create(context);
ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
} catch (Throwable e) {
reportWtf("starting NetworkManagement Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartTextServicesManagerService");
try {
- Slog.i(TAG, "Text Service Manager Service");
tsms = new TextServicesManagerService(context);
ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
} catch (Throwable e) {
reportWtf("starting Text Service Manager Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNetwork) {
+ traceBeginAndSlog("StartNetworkScoreService");
try {
- Slog.i(TAG, "Network Score Service");
networkScore = new NetworkScoreService(context);
ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
} catch (Throwable e) {
reportWtf("starting Network Score Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartNetworkStatsService");
try {
- Slog.i(TAG, "NetworkStats Service");
networkStats = new NetworkStatsService(context, networkManagement, alarm);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
} catch (Throwable e) {
reportWtf("starting NetworkStats Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartNetworkPolicyManagerService");
try {
- Slog.i(TAG, "NetworkPolicy Service");
networkPolicy = new NetworkPolicyManagerService(
context, mActivityManagerService,
(IPowerManager)ServiceManager.getService(Context.POWER_SERVICE),
@@ -690,6 +724,7 @@ public final class SystemServer {
} catch (Throwable e) {
reportWtf("starting NetworkPolicy Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
@@ -703,8 +738,8 @@ public final class SystemServer {
mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
}
+ traceBeginAndSlog("StartConnectivityService");
try {
- Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
@@ -713,25 +748,28 @@ public final class SystemServer {
} catch (Throwable e) {
reportWtf("starting Connectivity Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartNsdService");
try {
- Slog.i(TAG, "Network Service Discovery Service");
serviceDiscovery = NsdService.create(context);
ServiceManager.addService(
Context.NSD_SERVICE, serviceDiscovery);
} catch (Throwable e) {
reportWtf("starting Service Discovery Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartUpdateLockService");
try {
- Slog.i(TAG, "UpdateLock Service");
ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
new UpdateLockService(context));
} catch (Throwable e) {
reportWtf("starting UpdateLockService", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
/*
@@ -740,25 +778,31 @@ public final class SystemServer {
* first before continuing.
*/
if (mountService != null && !mOnlyCore) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WaitForAsecScan");
try {
mountService.waitForAsecScan();
} catch (RemoteException ignored) {
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAccountManagerServiceReady");
try {
if (accountManager != null)
accountManager.systemReady();
} catch (Throwable e) {
reportWtf("making Account Manager Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeContentServiceReady");
try {
if (contentService != null)
contentService.systemReady();
} catch (Throwable e) {
reportWtf("making Content Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mSystemServiceManager.startService(NotificationManagerService.class);
notification = INotificationManager.Stub.asInterface(
@@ -768,66 +812,72 @@ public final class SystemServer {
mSystemServiceManager.startService(DeviceStorageMonitorService.class);
if (!disableLocation) {
+ traceBeginAndSlog("StartLocationManagerService");
try {
- Slog.i(TAG, "Location Manager");
location = new LocationManagerService(context);
ServiceManager.addService(Context.LOCATION_SERVICE, location);
} catch (Throwable e) {
reportWtf("starting Location Manager", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartCountryDetectorService");
try {
- Slog.i(TAG, "Country Detector");
countryDetector = new CountryDetectorService(context);
ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
} catch (Throwable e) {
reportWtf("starting Country Detector", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartSearchManagerService");
try {
- Slog.i(TAG, "Search Service");
ServiceManager.addService(Context.SEARCH_SERVICE,
new SearchManagerService(context));
} catch (Throwable e) {
reportWtf("starting Search Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
mSystemServiceManager.startService(DropBoxManagerService.class);
if (!disableNonCoreServices && context.getResources().getBoolean(
R.bool.config_enableWallpaperService)) {
+ traceBeginAndSlog("StartWallpaperManagerService");
try {
- Slog.i(TAG, "Wallpaper Service");
wallpaper = new WallpaperManagerService(context);
ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
} catch (Throwable e) {
reportWtf("starting Wallpaper Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
+ traceBeginAndSlog("StartAudioService");
try {
- Slog.i(TAG, "Audio Service");
audioService = new AudioService(context);
ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
} catch (Throwable e) {
reportWtf("starting Audio Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (!disableNonCoreServices) {
mSystemServiceManager.startService(DockObserver.class);
}
+ traceBeginAndSlog("StartWiredAccessoryManager");
try {
- Slog.i(TAG, "Wired Accessory Manager");
// Listen for wired headset changes
inputManager.setWiredAccessoryCallbacks(
new WiredAccessoryManager(context, inputManager));
} catch (Throwable e) {
reportWtf("starting WiredAccessoryManager", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (!disableNonCoreServices) {
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
@@ -839,17 +889,20 @@ public final class SystemServer {
|| mPackageManager.hasSystemFeature(
PackageManager.FEATURE_USB_ACCESSORY)) {
// Manage USB host and device support
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartUsbService");
mSystemServiceManager.startService(USB_SERVICE_CLASS);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
+ traceBeginAndSlog("StartSerialService");
try {
- Slog.i(TAG, "Serial Service");
// Serial port support
serial = new SerialService(context);
ServiceManager.addService(Context.SERIAL_SERVICE, serial);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting SerialService", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
mSystemServiceManager.startService(TwilightService.class);
@@ -875,49 +928,54 @@ public final class SystemServer {
}
}
+ traceBeginAndSlog("StartDiskStatsService");
try {
- Slog.i(TAG, "DiskStats Service");
ServiceManager.addService("diskstats", new DiskStatsService(context));
} catch (Throwable e) {
reportWtf("starting DiskStats Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartSamplingProfilerService");
try {
// need to add this service even if SamplingProfilerIntegration.isEnabled()
// is false, because it is this service that detects system property change and
// turns on SamplingProfilerIntegration. Plus, when sampling profiler doesn't work,
// there is little overhead for running this service.
- Slog.i(TAG, "SamplingProfiler Service");
ServiceManager.addService("samplingprofiler",
new SamplingProfilerService(context));
} catch (Throwable e) {
reportWtf("starting SamplingProfiler Service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (!disableNetwork && !disableNetworkTime) {
+ traceBeginAndSlog("StartNetworkTimeUpdateService");
try {
- Slog.i(TAG, "NetworkTimeUpdateService");
networkTimeUpdater = new NetworkTimeUpdateService(context);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
+ traceBeginAndSlog("StartCommonTimeManagementService");
try {
- Slog.i(TAG, "CommonTimeManagementService");
commonTimeMgmtService = new CommonTimeManagementService(context);
ServiceManager.addService("commontime_management", commonTimeMgmtService);
} catch (Throwable e) {
reportWtf("starting CommonTimeManagementService service", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (!disableNetwork) {
+ traceBeginAndSlog("CertBlacklister");
try {
- Slog.i(TAG, "CertBlacklister");
CertBlacklister blacklister = new CertBlacklister(context);
} catch (Throwable e) {
reportWtf("starting CertBlacklister", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNonCoreServices) {
@@ -926,13 +984,14 @@ public final class SystemServer {
}
if (!disableNonCoreServices && ZygoteInit.PRELOAD_RESOURCES) {
+ traceBeginAndSlog("StartAssetAtlasService");
try {
- Slog.i(TAG, "Assets Atlas Service");
atlas = new AssetAtlasService(context);
ServiceManager.addService(AssetAtlasService.ASSET_ATLAS_SERVICE, atlas);
} catch (Throwable e) {
reportWtf("starting AssetAtlasService", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
if (!disableNonCoreServices) {
@@ -957,24 +1016,26 @@ public final class SystemServer {
}
if (!disableNonCoreServices) {
+ traceBeginAndSlog("StartMediaRouterService");
try {
- Slog.i(TAG, "Media Router Service");
mediaRouter = new MediaRouterService(context);
ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
} catch (Throwable e) {
reportWtf("starting MediaRouterService", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mSystemServiceManager.startService(TrustManagerService.class);
mSystemServiceManager.startService(FingerprintService.class);
+ traceBeginAndSlog("StartBackgroundDexOptService");
try {
- Slog.i(TAG, "BackgroundDexOptService");
BackgroundDexOptService.schedule(context, 0);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -1002,12 +1063,15 @@ public final class SystemServer {
// It is now time to start up the app processes...
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
try {
vibrator.systemReady();
} catch (Throwable e) {
reportWtf("making Vibrator Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeLockSettingsServiceReady");
if (lockSettings != null) {
try {
lockSettings.systemReady();
@@ -1015,17 +1079,20 @@ public final class SystemServer {
reportWtf("making Lock Settings Service ready", e);
}
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
// Needed by DevicePolicyManager for initialization
mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeWindowManagerServiceReady");
try {
wm.systemReady();
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (safeMode) {
mActivityManagerService.showSafeModeOverlay();
@@ -1046,25 +1113,32 @@ public final class SystemServer {
systemTheme.rebase();
}
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePowerManagerServiceReady");
try {
// TODO: use boot phase
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePackageManagerServiceReady");
try {
mPackageManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Package Manager Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeDisplayManagerServiceReady");
try {
// TODO: use boot phase and communicate these flags some other way
mDisplayManagerService.systemReady(safeMode, mOnlyCore);
} catch (Throwable e) {
reportWtf("making Display Manager Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
@@ -1098,55 +1172,76 @@ public final class SystemServer {
Slog.i(TAG, "Making services ready");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseActivityManagerReady");
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartObservingNativeCrashes");
try {
mActivityManagerService.startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Slog.i(TAG, "WebViewFactory preparation");
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
WebViewFactory.prepareWebViewInSystemServer();
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
try {
startSystemUi(context);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeMountServiceReady");
try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Score Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkManagementServiceReady");
try {
if (networkManagementF != null) networkManagementF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Managment Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkStatsServiceReady");
try {
if (networkStatsF != null) networkStatsF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Stats Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkPolicyServiceReady");
try {
if (networkPolicyF != null) networkPolicyF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Policy Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeConnectivityServiceReady");
try {
if (connectivityF != null) connectivityF.systemReady();
} catch (Throwable e) {
reportWtf("making Connectivity Service ready", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAudioServiceReady");
try {
if (audioServiceF != null) audioServiceF.systemReady();
} catch (Throwable e) {
reportWtf("Notifying AudioService running", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Watchdog.getInstance().start();
// It is now okay to let the various system services start their
// third party code...
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseThirdPartyAppsCanStart");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
@@ -1215,6 +1310,7 @@ public final class SystemServer {
} catch (Throwable e) {
reportWtf("Notifying MmsService running", e);
}
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
});
}
@@ -1226,4 +1322,9 @@ public final class SystemServer {
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
}
+
+ private static void traceBeginAndSlog(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ Slog.i(TAG, name);
+ }
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2d31a78bb617..8a1a55378321 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -206,8 +206,14 @@ public final class Call {
*/
public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
+ /**
+ * Call sends responses through connection.
+ * @hide
+ */
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
//******************************************************************************************
- // Next CAPABILITY value: 0x00004000
+ // Next CAPABILITY value: 0x00800000
//******************************************************************************************
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7b277c5dcc94..430760a892b7 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -248,8 +248,15 @@ public abstract class Connection extends Conferenceable {
*/
public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
+ /**
+ * Indicates that the connection itself wants to handle any sort of reply response, rather than
+ * relying on SMS.
+ * @hide
+ */
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
//**********************************************************************************************
- // Next CAPABILITY value: 0x00400000
+ // Next CAPABILITY value: 0x00800000
//**********************************************************************************************
/**
@@ -388,6 +395,10 @@ public abstract class Connection extends Conferenceable {
if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+ builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
+ }
+
builder.append("]");
return builder.toString();
}
@@ -1763,6 +1774,13 @@ public abstract class Connection extends Conferenceable {
public void onReject() {}
/**
+ * Notifies ths Connection of a request reject with a message.
+ *
+ * @hide
+ */
+ public void onReject(String replyMessage) {}
+
+ /**
* Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
*/
public void onPostDialContinue(boolean proceed) {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 383e45b75fb0..4e330bdbf67d 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -101,6 +101,7 @@ public abstract class ConnectionService extends Service {
private static final int MSG_ANSWER_VIDEO = 17;
private static final int MSG_MERGE_CONFERENCE = 18;
private static final int MSG_SWAP_CONFERENCE = 19;
+ private static final int MSG_REJECT_WITH_MESSAGE = 20;
private static Connection sNullConnection;
@@ -166,6 +167,14 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void rejectWithMessage(String callId, String message) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = message;
+ mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
+ }
+
+ @Override
public void disconnect(String callId) {
mHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
}
@@ -296,6 +305,15 @@ public abstract class ConnectionService extends Service {
case MSG_REJECT:
reject((String) msg.obj);
break;
+ case MSG_REJECT_WITH_MESSAGE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ reject((String) args.arg1, (String) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_DISCONNECT:
disconnect((String) msg.obj);
break;
@@ -681,6 +699,11 @@ public abstract class ConnectionService extends Service {
findConnectionForAction(callId, "reject").onReject();
}
+ private void reject(String callId, String rejectWithMessage) {
+ Log.d(this, "reject %s with message", callId);
+ findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
+ }
+
private void disconnect(String callId) {
Log.d(this, "disconnect %s", callId);
if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index c2e8530b2dbd..dd253cfdfbe4 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -50,6 +50,8 @@ oneway interface IConnectionService {
void reject(String callId);
+ void rejectWithMessage(String callId, String message);
+
void disconnect(String callId);
void hold(String callId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bfb7a50f461e..aa750eff807a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -419,6 +419,15 @@ public class CarrierConfigManager {
public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
+ /**
+ * Determines whether the carrier supports making non-emergency phone calls while the phone is
+ * in emergency callback mode. Default value is {@code true}, meaning that non-emergency calls
+ * are allowed in emergency callback mode.
+ * @hide
+ */
+ public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
+ "allow_non_emergency_calls_in_ecm_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -513,6 +522,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_MMS_UA_PROF_TAG_NAME_STRING, "x-wap-profile");
sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, "");
sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
+ sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
}
/**
diff --git a/tests/SurfaceComposition/Android.mk b/tests/SurfaceComposition/Android.mk
new file mode 100644
index 000000000000..95f69f179c20
--- /dev/null
+++ b/tests/SurfaceComposition/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SurfaceComposition
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SurfaceComposition/AndroidManifest.xml b/tests/SurfaceComposition/AndroidManifest.xml
new file mode 100644
index 000000000000..4c0a9b61fd8f
--- /dev/null
+++ b/tests/SurfaceComposition/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.surfacecomposition">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <application android:theme="@style/noeffects">
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.surfacecomposition.SurfaceCompositionMeasuringActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="android.surfacecomposition">
+ </instrumentation>
+</manifest>
diff --git a/tests/SurfaceComposition/res/values/themes.xml b/tests/SurfaceComposition/res/values/themes.xml
new file mode 100644
index 000000000000..254d707134aa
--- /dev/null
+++ b/tests/SurfaceComposition/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+<resources>
+ <style name="noeffects" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:fadingEdge">none</item>
+ <item name="android:windowContentTransitions">false</item>
+ <item name="android:windowAnimationStyle">@null</item>
+ </style>
+</resources>
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java b/tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java
new file mode 100644
index 000000000000..d626f10b42cb
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java
@@ -0,0 +1,48 @@
+/*
+ * 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.surfacecomposition;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class CustomLayout extends ViewGroup {
+ public CustomLayout(Context context) {
+ super(context);
+ }
+
+ public static class LayoutParams extends ViewGroup.LayoutParams {
+ private int mLeft, mTop, mRight, mBottom;
+
+ public LayoutParams(int left, int top, int right, int bottom) {
+ super(0, 0);
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ CustomLayout.LayoutParams lp = (CustomLayout.LayoutParams) child.getLayoutParams();
+ child.layout(lp.mLeft, lp.mTop, lp.mRight, lp.mBottom);
+ }
+ }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java b/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java
new file mode 100644
index 000000000000..0430662873cf
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java
@@ -0,0 +1,243 @@
+/*
+ * 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.surfacecomposition;
+
+import java.util.Random;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * This provides functionality to measure Surface update frame rate. The idea is to
+ * constantly invalidates Surface in a separate thread. Lowest possible way is to
+ * use SurfaceView which works with Surface. This gives a very small overhead
+ * and very close to Android internals. Note, that lockCanvas is blocking
+ * methods and it returns once SurfaceFlinger consumes previous buffer. This
+ * gives the change to measure real performance of Surface compositor.
+ */
+public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+ private final static long DURATION_TO_WARMUP_MS = 50;
+ private final static long DURATION_TO_MEASURE_ROUGH_MS = 500;
+ private final static long DURATION_TO_MEASURE_PRECISE_MS = 3000;
+ private final static Random mRandom = new Random();
+
+ private final Object mSurfaceLock = new Object();
+ private Surface mSurface;
+ private boolean mDrawNameOnReady = true;
+ private boolean mSurfaceWasChanged = false;
+ private String mName;
+ private Canvas mCanvas;
+
+ class ValidateThread extends Thread {
+ private double mFPS = 0.0f;
+ // Used to support early exit and prevent long computation.
+ private double mBadFPS;
+ private double mPerfectFPS;
+
+ ValidateThread(double badFPS, double perfectFPS) {
+ mBadFPS = badFPS;
+ mPerfectFPS = perfectFPS;
+ }
+
+ public void run() {
+ long startTime = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startTime < DURATION_TO_WARMUP_MS) {
+ invalidateSurface(false);
+ }
+
+ startTime = System.currentTimeMillis();
+ long endTime;
+ int frameCnt = 0;
+ while (true) {
+ invalidateSurface(false);
+ endTime = System.currentTimeMillis();
+ ++frameCnt;
+ mFPS = (double)frameCnt * 1000.0 / (endTime - startTime);
+ if ((endTime - startTime) >= DURATION_TO_MEASURE_ROUGH_MS) {
+ // Test if result looks too bad or perfect and stop early.
+ if (mFPS <= mBadFPS || mFPS >= mPerfectFPS) {
+ break;
+ }
+ }
+ if ((endTime - startTime) >= DURATION_TO_MEASURE_PRECISE_MS) {
+ break;
+ }
+ }
+ }
+
+ public double getFPS() {
+ return mFPS;
+ }
+ }
+
+ public CustomSurfaceView(Context context, String name) {
+ super(context);
+ mName = name;
+ getHolder().addCallback(this);
+ }
+
+ public void setMode(int pixelFormat, boolean drawNameOnReady) {
+ mDrawNameOnReady = drawNameOnReady;
+ getHolder().setFormat(pixelFormat);
+ }
+
+ public void acquireCanvas() {
+ synchronized (mSurfaceLock) {
+ if (mCanvas != null) {
+ throw new RuntimeException("Surface canvas was already acquired.");
+ }
+ if (mSurface != null) {
+ mCanvas = mSurface.lockCanvas(null);
+ }
+ }
+ }
+
+ public void releaseCanvas() {
+ synchronized (mSurfaceLock) {
+ if (mCanvas != null) {
+ if (mSurface == null) {
+ throw new RuntimeException(
+ "Surface was destroyed but canvas was not released.");
+ }
+ mSurface.unlockCanvasAndPost(mCanvas);
+ mCanvas = null;
+ }
+ }
+ }
+
+ /**
+ * Invalidate surface.
+ */
+ private void invalidateSurface(boolean drawSurfaceId) {
+ synchronized (mSurfaceLock) {
+ if (mSurface != null) {
+ Canvas canvas = mSurface.lockCanvas(null);
+ // Draw surface name for debug purpose only. This does not affect the test
+ // because it is drawn only during allocation.
+ if (drawSurfaceId) {
+ int textSize = canvas.getHeight() / 24;
+ Paint paint = new Paint();
+ paint.setTextSize(textSize);
+ int textWidth = (int)(paint.measureText(mName) + 0.5f);
+ int x = mRandom.nextInt(canvas.getWidth() - textWidth);
+ int y = textSize + mRandom.nextInt(canvas.getHeight() - textSize);
+ // Create effect of fog to visually control correctness of composition.
+ paint.setColor(0xFFFF8040);
+ canvas.drawARGB(32, 255, 255, 255);
+ canvas.drawText(mName, x, y, paint);
+ }
+ mSurface.unlockCanvasAndPost(canvas);
+ }
+ }
+ }
+
+ /**
+ * Wait until surface is created and ready to use or return immediately if surface
+ * already exists.
+ */
+ public void waitForSurfaceReady() {
+ synchronized (mSurfaceLock) {
+ if (mSurface == null) {
+ try {
+ mSurfaceLock.wait(5000);
+ } catch(InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if (mSurface == null)
+ throw new RuntimeException("Surface is not ready.");
+ mSurfaceWasChanged = false;
+ }
+ }
+
+ /**
+ * Wait until surface is destroyed or return immediately if surface does not exist.
+ */
+ public void waitForSurfaceDestroyed() {
+ synchronized (mSurfaceLock) {
+ if (mSurface != null) {
+ try {
+ mSurfaceLock.wait(5000);
+ } catch(InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if (mSurface != null)
+ throw new RuntimeException("Surface still exists.");
+ mSurfaceWasChanged = false;
+ }
+ }
+
+ /**
+ * Validate that surface has not been changed since waitForSurfaceReady or
+ * waitForSurfaceDestroyed.
+ */
+ public void validateSurfaceNotChanged() {
+ synchronized (mSurfaceLock) {
+ if (mSurfaceWasChanged) {
+ throw new RuntimeException("Surface was changed during the test execution.");
+ }
+ }
+ }
+
+ public double measureFPS(double badFPS, double perfectFPS) {
+ try {
+ ValidateThread validateThread = new ValidateThread(badFPS, perfectFPS);
+ validateThread.start();
+ validateThread.join();
+ return validateThread.getFPS();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ synchronized (mSurfaceLock) {
+ mSurfaceWasChanged = true;
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // This method is always called at least once, after surfaceCreated.
+ synchronized (mSurfaceLock) {
+ mSurface = holder.getSurface();
+ // We only need to invalidate the surface for the compositor performance test so that
+ // it gets included in the composition process. For allocation performance we
+ // don't need to invalidate surface and this allows us to remove non-necessary
+ // surface invalidation from the test.
+ if (mDrawNameOnReady) {
+ invalidateSurface(true);
+ }
+ mSurfaceWasChanged = true;
+ mSurfaceLock.notify();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ synchronized (mSurfaceLock) {
+ mSurface = null;
+ mSurfaceWasChanged = true;
+ mSurfaceLock.notify();
+ }
+ }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java b/tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java
new file mode 100644
index 000000000000..c716daee2fa6
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java
@@ -0,0 +1,71 @@
+/*
+ * 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.surfacecomposition;
+
+import android.util.Log;
+
+/**
+ * This task will simulate CPU activity by consuming memory bandwidth from the system.
+ * Note: On most system the CPU and GPU will share the same memory.
+ */
+public class MemoryAccessTask {
+ private final static String TAG = "MemoryAccessTask";
+ private final static int BUFFER_SIZE = 32 * 1024 * 1024;
+ private final static int BUFFER_STEP = 256;
+ private boolean mStopRequested;
+ private WorkThread mThread;
+ private final Object mLock = new Object();
+
+ public class WorkThread extends Thread {
+ public void run() {
+ byte[] memory = new byte[BUFFER_SIZE];
+ while (true) {
+ synchronized (mLock) {
+ if (mStopRequested) {
+ break;
+ }
+ }
+ long result = 0;
+ for (int index = 0; index < BUFFER_SIZE; index += BUFFER_STEP) {
+ result += ++memory[index];
+ }
+ Log.v(TAG, "Processing...:" + result);
+ }
+ }
+ }
+
+ public void start() {
+ if (mThread != null) {
+ throw new RuntimeException("Work thread is already started");
+ }
+ mStopRequested = false;
+ mThread = new WorkThread();
+ mThread.start();
+ }
+
+ public void stop() {
+ if (mThread != null) {
+ synchronized (mLock) {
+ mStopRequested = true;
+ }
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
new file mode 100644
index 000000000000..e3e1d34f193e
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
@@ -0,0 +1,602 @@
+/*
+ * 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.surfacecomposition;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.MemoryInfo;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+/**
+ * This activity is designed to measure peformance scores of Android surfaces.
+ * It can work in two modes. In first mode functionality of this activity is
+ * invoked from Cts test (SurfaceCompositionTest). This activity can also be
+ * used in manual mode as a normal app. Different pixel formats are supported.
+ *
+ * measureCompositionScore(pixelFormat)
+ * This test measures surface compositor performance which shows how many
+ * surfaces of specific format surface compositor can combine without dropping
+ * frames. We allow one dropped frame per half second.
+ *
+ * measureAllocationScore(pixelFormat)
+ * This test measures surface allocation/deallocation performance. It shows
+ * how many surface lifecycles (creation, destruction) can be done per second.
+ *
+ * In manual mode, which activated by pressing button 'Compositor speed' or
+ * 'Allocator speed', all possible pixel format are tested and combined result
+ * is displayed in text view. Additional system information such as memory
+ * status, display size and surface format is also displayed and regulary
+ * updated.
+ */
+public class SurfaceCompositionMeasuringActivity extends Activity implements OnClickListener {
+ private final static int MIN_NUMBER_OF_SURFACES = 15;
+ private final static int MAX_NUMBER_OF_SURFACES = 40;
+ private final static int WARM_UP_ALLOCATION_CYCLES = 2;
+ private final static int MEASURE_ALLOCATION_CYCLES = 5;
+ private final static int TEST_COMPOSITOR = 1;
+ private final static int TEST_ALLOCATION = 2;
+ private final static float MIN_REFRESH_RATE_SUPPORTED = 50.0f;
+
+ private final static DecimalFormat DOUBLE_FORMAT = new DecimalFormat("#.00");
+ // Possible selection in pixel format selector.
+ private final static int[] PIXEL_FORMATS = new int[] {
+ PixelFormat.TRANSLUCENT,
+ PixelFormat.TRANSPARENT,
+ PixelFormat.OPAQUE,
+ PixelFormat.RGBA_8888,
+ PixelFormat.RGBX_8888,
+ PixelFormat.RGB_888,
+ PixelFormat.RGB_565,
+ };
+
+
+ private List<CustomSurfaceView> mViews = new ArrayList<CustomSurfaceView>();
+ private Button mMeasureCompositionButton;
+ private Button mMeasureAllocationButton;
+ private Spinner mPixelFormatSelector;
+ private TextView mResultView;
+ private TextView mSystemInfoView;
+ private final Object mLockResumed = new Object();
+ private boolean mResumed;
+
+ // Drop one frame per half second.
+ // TODO(khmel)
+ // Add a feature flag and set the target FPS dependent on the target system as e.g.:
+ // 59FPS for MULTI_WINDOW and 54 otherwise (to satisfy the default lax Android requirements).
+ private double mRefreshRate;
+ private double mTargetFPS;
+
+ private int mWidth;
+ private int mHeight;
+
+ class CompositorScore {
+ double mSurfaces;
+ double mBitrate;
+
+ @Override
+ public String toString() {
+ return DOUBLE_FORMAT.format(mSurfaces) + " surfaces. " +
+ "Bitrate: " + getReadableMemory((long)mBitrate) + "/s";
+ }
+ }
+
+ /**
+ * Measure performance score.
+ *
+ * @return biggest possible number of visible surfaces which surface
+ * compositor can handle.
+ */
+ public CompositorScore measureCompositionScore(int pixelFormat) {
+ waitForActivityResumed();
+ //MemoryAccessTask memAccessTask = new MemoryAccessTask();
+ //memAccessTask.start();
+ // Destroy any active surface.
+ configureSurfacesAndWait(0, pixelFormat, false);
+ CompositorScore score = new CompositorScore();
+ score.mSurfaces = measureCompositionScore(new Measurement(0, 60.0),
+ new Measurement(mViews.size() + 1, 0.0f), pixelFormat);
+ // Assume 32 bits per pixel.
+ score.mBitrate = score.mSurfaces * mTargetFPS * mWidth * mHeight * 4.0;
+ //memAccessTask.stop();
+ return score;
+ }
+
+ static class AllocationScore {
+ double mMedian;
+ double mMin;
+ double mMax;
+
+ @Override
+ public String toString() {
+ return DOUBLE_FORMAT.format(mMedian) + " (min:" + DOUBLE_FORMAT.format(mMin) +
+ ", max:" + DOUBLE_FORMAT.format(mMax) + ") surface allocations per second";
+ }
+ }
+
+ public AllocationScore measureAllocationScore(int pixelFormat) {
+ waitForActivityResumed();
+ AllocationScore score = new AllocationScore();
+ for (int i = 0; i < MEASURE_ALLOCATION_CYCLES + WARM_UP_ALLOCATION_CYCLES; ++i) {
+ long time1 = System.currentTimeMillis();
+ configureSurfacesAndWait(MIN_NUMBER_OF_SURFACES, pixelFormat, false);
+ acquireSurfacesCanvas();
+ long time2 = System.currentTimeMillis();
+ releaseSurfacesCanvas();
+ configureSurfacesAndWait(0, pixelFormat, false);
+ // Give SurfaceFlinger some time to rebuild the layer stack and release the buffers.
+ try {
+ Thread.sleep(500);
+ } catch(InterruptedException e) {
+ e.printStackTrace();
+ }
+ if (i < WARM_UP_ALLOCATION_CYCLES) {
+ // This is warm-up cycles, ignore result so far.
+ continue;
+ }
+ double speed = MIN_NUMBER_OF_SURFACES * 1000.0 / (time2 - time1);
+ score.mMedian += speed / MEASURE_ALLOCATION_CYCLES;
+ if (i == WARM_UP_ALLOCATION_CYCLES) {
+ score.mMin = speed;
+ score.mMax = speed;
+ } else {
+ score.mMin = Math.min(score.mMin, speed);
+ score.mMax = Math.max(score.mMax, speed);
+ }
+ }
+
+ return score;
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == mMeasureCompositionButton) {
+ doTest(TEST_COMPOSITOR);
+ } else if (view == mMeasureAllocationButton) {
+ doTest(TEST_ALLOCATION);
+ }
+ }
+
+ private void doTest(final int test) {
+ enableControls(false);
+ final int pixelFormat = PIXEL_FORMATS[mPixelFormatSelector.getSelectedItemPosition()];
+ new Thread() {
+ public void run() {
+ final StringBuffer sb = new StringBuffer();
+ switch (test) {
+ case TEST_COMPOSITOR: {
+ sb.append("Compositor score:");
+ CompositorScore score = measureCompositionScore(pixelFormat);
+ sb.append("\n " + getPixelFormatInfo(pixelFormat) + ":" +
+ score + ".");
+ }
+ break;
+ case TEST_ALLOCATION: {
+ sb.append("Allocation score:");
+ AllocationScore score = measureAllocationScore(pixelFormat);
+ sb.append("\n " + getPixelFormatInfo(pixelFormat) + ":" +
+ score + ".");
+ }
+ break;
+ }
+ runOnUiThreadAndWait(new Runnable() {
+ public void run() {
+ mResultView.setText(sb.toString());
+ enableControls(true);
+ updateSystemInfo(pixelFormat);
+ }
+ });
+ }
+ }.start();
+ }
+
+ /**
+ * Wait until activity is resumed.
+ */
+ public void waitForActivityResumed() {
+ synchronized (mLockResumed) {
+ if (!mResumed) {
+ try {
+ mLockResumed.wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (!mResumed) {
+ throw new RuntimeException("Activity was not resumed");
+ }
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ detectRefreshRate();
+
+ // To layouts in parent. First contains list of Surfaces and second
+ // controls. Controls stay on top.
+ RelativeLayout rootLayout = new RelativeLayout(this);
+ rootLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ CustomLayout layout = new CustomLayout(this);
+ layout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ Rect rect = new Rect();
+ getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+ mWidth = rect.right;
+ mHeight = rect.bottom;
+ long maxMemoryPerSurface = roundToNextPowerOf2(mWidth) * roundToNextPowerOf2(mHeight) * 4;
+ // Use 75% of available memory.
+ int surfaceCnt = (int)((getMemoryInfo().availMem * 3) / (4 * maxMemoryPerSurface));
+ if (surfaceCnt < MIN_NUMBER_OF_SURFACES) {
+ throw new RuntimeException("Not enough memory to allocate " +
+ MIN_NUMBER_OF_SURFACES + " surfaces.");
+ }
+ if (surfaceCnt > MAX_NUMBER_OF_SURFACES) {
+ surfaceCnt = MAX_NUMBER_OF_SURFACES;
+ }
+
+ LinearLayout controlLayout = new LinearLayout(this);
+ controlLayout.setOrientation(LinearLayout.VERTICAL);
+ controlLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ mMeasureCompositionButton = createButton("Compositor speed.", controlLayout);
+ mMeasureAllocationButton = createButton("Allocation speed", controlLayout);
+
+ String[] pixelFomats = new String[PIXEL_FORMATS.length];
+ for (int i = 0; i < pixelFomats.length; ++i) {
+ pixelFomats[i] = getPixelFormatInfo(PIXEL_FORMATS[i]);
+ }
+ mPixelFormatSelector = new Spinner(this);
+ ArrayAdapter<String> pixelFormatSelectorAdapter =
+ new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, pixelFomats);
+ pixelFormatSelectorAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ mPixelFormatSelector.setAdapter(pixelFormatSelectorAdapter);
+ mPixelFormatSelector.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ controlLayout.addView(mPixelFormatSelector);
+
+ mResultView = new TextView(this);
+ mResultView.setBackgroundColor(0);
+ mResultView.setText("Press button to start test.");
+ mResultView.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ controlLayout.addView(mResultView);
+
+ mSystemInfoView = new TextView(this);
+ mSystemInfoView.setBackgroundColor(0);
+ mSystemInfoView.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ controlLayout.addView(mSystemInfoView);
+
+ for (int i = 0; i < surfaceCnt; ++i) {
+ CustomSurfaceView view = new CustomSurfaceView(this, "Surface:" + i);
+ // Create all surfaces overlapped in order to prevent SurfaceFlinger
+ // to filter out surfaces by optimization in case surface is opaque.
+ // In case surface is transparent it will be drawn anyway. Note that first
+ // surface covers whole screen and must stand below other surfaces. Z order of
+ // layers is not predictable and there is only one way to force first
+ // layer to be below others is to mark it as media and all other layers
+ // to mark as media overlay.
+ if (i == 0) {
+ view.setLayoutParams(new CustomLayout.LayoutParams(0, 0, mWidth, mHeight));
+ view.setZOrderMediaOverlay(false);
+ } else {
+ // Z order of other layers is not predefined so make offset on x and reverse
+ // offset on y to make sure that surface is visible in any layout.
+ int x = i;
+ int y = (surfaceCnt - i);
+ view.setLayoutParams(new CustomLayout.LayoutParams(x, y, x + mWidth, y + mHeight));
+ view.setZOrderMediaOverlay(true);
+ }
+ view.setVisibility(View.INVISIBLE);
+ layout.addView(view);
+ mViews.add(view);
+ }
+
+ rootLayout.addView(layout);
+ rootLayout.addView(controlLayout);
+
+ setContentView(rootLayout);
+ }
+
+ private Button createButton(String caption, LinearLayout layout) {
+ Button button = new Button(this);
+ button.setText(caption);
+ button.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ button.setOnClickListener(this);
+ layout.addView(button);
+ return button;
+ }
+
+ private void enableControls(boolean enabled) {
+ mMeasureCompositionButton.setEnabled(enabled);
+ mMeasureAllocationButton.setEnabled(enabled);
+ mPixelFormatSelector.setEnabled(enabled);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ updateSystemInfo(PixelFormat.UNKNOWN);
+
+ synchronized (mLockResumed) {
+ mResumed = true;
+ mLockResumed.notifyAll();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ synchronized (mLockResumed) {
+ mResumed = false;
+ }
+ }
+
+ class Measurement {
+ Measurement(int surfaceCnt, double fps) {
+ mSurfaceCnt = surfaceCnt;
+ mFPS = fps;
+ }
+
+ public final int mSurfaceCnt;
+ public final double mFPS;
+ }
+
+ private double measureCompositionScore(Measurement ok, Measurement fail, int pixelFormat) {
+ if (ok.mSurfaceCnt + 1 == fail.mSurfaceCnt) {
+ // Interpolate result.
+ double fraction = (mTargetFPS - fail.mFPS) / (ok.mFPS - fail.mFPS);
+ return ok.mSurfaceCnt + fraction;
+ }
+
+ int medianSurfaceCnt = (ok.mSurfaceCnt + fail.mSurfaceCnt) / 2;
+ Measurement median = new Measurement(medianSurfaceCnt,
+ measureFPS(medianSurfaceCnt, pixelFormat));
+
+ if (median.mFPS >= mTargetFPS) {
+ return measureCompositionScore(median, fail, pixelFormat);
+ } else {
+ return measureCompositionScore(ok, median, pixelFormat);
+ }
+ }
+
+ private double measureFPS(int surfaceCnt, int pixelFormat) {
+ configureSurfacesAndWait(surfaceCnt, pixelFormat, true);
+ // At least one view is visible and it is enough to update only
+ // one overlapped surface in order to force SurfaceFlinger to send
+ // all surfaces to compositor.
+ double fps = mViews.get(0).measureFPS(mRefreshRate * 0.8, mRefreshRate * 0.999);
+
+ // Make sure that surface configuration was not changed.
+ validateSurfacesNotChanged();
+
+ return fps;
+ }
+
+ private void waitForSurfacesConfigured(final int pixelFormat) {
+ for (int i = 0; i < mViews.size(); ++i) {
+ CustomSurfaceView view = mViews.get(i);
+ if (view.getVisibility() == View.VISIBLE) {
+ view.waitForSurfaceReady();
+ } else {
+ view.waitForSurfaceDestroyed();
+ }
+ }
+ runOnUiThreadAndWait(new Runnable() {
+ @Override
+ public void run() {
+ updateSystemInfo(pixelFormat);
+ }
+ });
+ }
+
+ private void validateSurfacesNotChanged() {
+ for (int i = 0; i < mViews.size(); ++i) {
+ CustomSurfaceView view = mViews.get(i);
+ view.validateSurfaceNotChanged();
+ }
+ }
+
+ private void configureSurfaces(int surfaceCnt, int pixelFormat, boolean invalidate) {
+ for (int i = 0; i < mViews.size(); ++i) {
+ CustomSurfaceView view = mViews.get(i);
+ if (i < surfaceCnt) {
+ view.setMode(pixelFormat, invalidate);
+ view.setVisibility(View.VISIBLE);
+ } else {
+ view.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ private void configureSurfacesAndWait(final int surfaceCnt, final int pixelFormat,
+ final boolean invalidate) {
+ runOnUiThreadAndWait(new Runnable() {
+ @Override
+ public void run() {
+ configureSurfaces(surfaceCnt, pixelFormat, invalidate);
+ }
+ });
+ waitForSurfacesConfigured(pixelFormat);
+ }
+
+ private void acquireSurfacesCanvas() {
+ for (int i = 0; i < mViews.size(); ++i) {
+ CustomSurfaceView view = mViews.get(i);
+ view.acquireCanvas();
+ }
+ }
+
+ private void releaseSurfacesCanvas() {
+ for (int i = 0; i < mViews.size(); ++i) {
+ CustomSurfaceView view = mViews.get(i);
+ view.releaseCanvas();
+ }
+ }
+
+ private static String getReadableMemory(long bytes) {
+ long unit = 1024;
+ if (bytes < unit) {
+ return bytes + " B";
+ }
+ int exp = (int) (Math.log(bytes) / Math.log(unit));
+ return String.format("%.1f %sB", bytes / Math.pow(unit, exp),
+ "KMGTPE".charAt(exp-1));
+ }
+
+ private MemoryInfo getMemoryInfo() {
+ ActivityManager activityManager = (ActivityManager)
+ getSystemService(ACTIVITY_SERVICE);
+ MemoryInfo memInfo = new MemoryInfo();
+ activityManager.getMemoryInfo(memInfo);
+ return memInfo;
+ }
+
+ private void updateSystemInfo(int pixelFormat) {
+ int visibleCnt = 0;
+ for (int i = 0; i < mViews.size(); ++i) {
+ if (mViews.get(i).getVisibility() == View.VISIBLE) {
+ ++visibleCnt;
+ }
+ }
+
+ MemoryInfo memInfo = getMemoryInfo();
+ String info = "Available " +
+ getReadableMemory(memInfo.availMem) + " from " +
+ getReadableMemory(memInfo.totalMem) + ".\nVisible " +
+ visibleCnt + " from " + mViews.size() + " " +
+ getPixelFormatInfo(pixelFormat) + " surfaces.\n" +
+ "View size: " + mWidth + "x" + mHeight +
+ ". Refresh rate: " + DOUBLE_FORMAT.format(mRefreshRate) + ".";
+ mSystemInfoView.setText(info);
+ }
+
+ private void detectRefreshRate() {
+ WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
+ mRefreshRate = wm.getDefaultDisplay().getRefreshRate();
+ if (mRefreshRate < MIN_REFRESH_RATE_SUPPORTED)
+ throw new RuntimeException("Unsupported display refresh rate: " + mRefreshRate);
+ mTargetFPS = mRefreshRate - 2.0f;
+ }
+
+ private int roundToNextPowerOf2(int value) {
+ --value;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ return value + 1;
+ }
+
+ public static String getPixelFormatInfo(int pixelFormat) {
+ switch (pixelFormat) {
+ case PixelFormat.TRANSLUCENT:
+ return "TRANSLUCENT";
+ case PixelFormat.TRANSPARENT:
+ return "TRANSPARENT";
+ case PixelFormat.OPAQUE:
+ return "OPAQUE";
+ case PixelFormat.RGBA_8888:
+ return "RGBA_8888";
+ case PixelFormat.RGBX_8888:
+ return "RGBX_8888";
+ case PixelFormat.RGB_888:
+ return "RGB_888";
+ case PixelFormat.RGB_565:
+ return "RGB_565";
+ default:
+ return "PIX.FORMAT:" + pixelFormat;
+ }
+ }
+
+ /**
+ * A helper that executes a task in the UI thread and waits for its completion.
+ *
+ * @param task - task to execute.
+ */
+ private void runOnUiThreadAndWait(Runnable task) {
+ new UIExecutor(task);
+ }
+
+ class UIExecutor implements Runnable {
+ private final Object mLock = new Object();
+ private Runnable mTask;
+ private boolean mDone = false;
+
+ UIExecutor(Runnable task) {
+ mTask = task;
+ mDone = false;
+ runOnUiThread(this);
+ synchronized (mLock) {
+ while (!mDone) {
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void run() {
+ mTask.run();
+ synchronized (mLock) {
+ mDone = true;
+ mLock.notify();
+ }
+ }
+ }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
new file mode 100644
index 000000000000..6e9e7390c2c1
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.surfacecomposition;
+
+import android.graphics.PixelFormat;
+import android.surfacecomposition.SurfaceCompositionMeasuringActivity.AllocationScore;
+import android.surfacecomposition.SurfaceCompositionMeasuringActivity.CompositorScore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+public class SurfaceCompositionTest extends
+ ActivityInstrumentationTestCase2<SurfaceCompositionMeasuringActivity> {
+ private final static String TAG = "SurfaceCompositionTest";
+
+ // Pass threshold for major pixel formats.
+ private final static int[] TEST_PIXEL_FORMATS = new int[] {
+ PixelFormat.TRANSLUCENT,
+ PixelFormat.OPAQUE,
+ };
+
+ // Based on Nexus 9 performance which is usually < 9.0.
+ private final static double[] MIN_ACCEPTED_COMPOSITION_SCORE = new double[] {
+ 8.0,
+ 8.0,
+ };
+
+ // Based on Nexus 6 performance which is usually < 28.0.
+ private final static double[] MIN_ACCEPTED_ALLOCATION_SCORE = new double[] {
+ 20.0,
+ 20.0,
+ };
+
+ public SurfaceCompositionTest() {
+ super(SurfaceCompositionMeasuringActivity.class);
+ }
+
+ private void testRestoreContexts() {
+ }
+
+ @SmallTest
+ public void testSurfaceCompositionPerformance() {
+ for (int i = 0; i < TEST_PIXEL_FORMATS.length; ++i) {
+ int pixelFormat = TEST_PIXEL_FORMATS[i];
+ String formatName = SurfaceCompositionMeasuringActivity.getPixelFormatInfo(pixelFormat);
+ CompositorScore score = getActivity().measureCompositionScore(pixelFormat);
+ Log.i(TAG, "testSurfaceCompositionPerformance(" + formatName + ") = " + score);
+ assertTrue("Device does not support surface(" + formatName + ") composition " +
+ "performance score. " + score.mSurfaces + " < " +
+ MIN_ACCEPTED_COMPOSITION_SCORE[i] + ".",
+ score.mSurfaces >= MIN_ACCEPTED_COMPOSITION_SCORE[i]);
+ }
+ }
+
+ @SmallTest
+ public void testSurfaceAllocationPerformance() {
+ for (int i = 0; i < TEST_PIXEL_FORMATS.length; ++i) {
+ int pixelFormat = TEST_PIXEL_FORMATS[i];
+ String formatName = SurfaceCompositionMeasuringActivity.getPixelFormatInfo(pixelFormat);
+ AllocationScore score = getActivity().measureAllocationScore(pixelFormat);
+ Log.i(TAG, "testSurfaceAllocationPerformance(" + formatName + ") = " + score);
+ assertTrue("Device does not support surface(" + formatName + ") allocation " +
+ "performance score. " + score.mMedian + " < " +
+ MIN_ACCEPTED_ALLOCATION_SCORE[i] + ".",
+ score.mMedian >= MIN_ACCEPTED_ALLOCATION_SCORE[i]);
+ }
+ }
+}
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index d9df9f88b50c..f892a68eea39 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -14,11 +14,13 @@
~ limitations under the License
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.uibench">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.test.uibench">
<application
android:allowBackup="false"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
+ tools:ignore="MissingApplicationIcon">
<uses-library android:name="android.test.runner" />
<!-- Root navigation activity -->
@@ -34,6 +36,14 @@
<!-- General -->
<activity
+ android:name=".DialogListActivity"
+ android:label="General/Dialog List" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name=".GlTextureViewActivity"
android:label="General/GL TextureView" >
<intent-filter>
@@ -74,10 +84,28 @@
</intent-filter>
</activity>
- <!-- GPU -->
+ <!-- Rendering -->
<activity
android:name=".BitmapUploadActivity"
- android:label="GPU/Bitmap Upload" >
+ android:label="Rendering/Bitmap Upload" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ShadowGridActivity"
+ android:label="Rendering/Shadow Grid" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+
+ <!-- Inflation -->
+ <activity
+ android:name=".InflatingListActivity"
+ android:label="Inflation/Inflating ListView" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.uibench.TEST" />
diff --git a/tests/UiBench/res/layout/card_row.xml b/tests/UiBench/res/layout/card_row.xml
new file mode 100644
index 000000000000..215f9df9b7fd
--- /dev/null
+++ b/tests/UiBench/res/layout/card_row.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp"
+ android:paddingTop="5dp"
+ android:paddingBottom="5dp"
+ android:clipToPadding="false"
+ android:background="@null">
+ <android.support.v7.widget.CardView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+ <TextView
+ android:id="@+id/card_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </android.support.v7.widget.CardView>
+
+ <android.support.v4.widget.Space
+ android:layout_height="match_parent"
+ android:layout_width="10dp" />
+
+ <android.support.v7.widget.CardView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+</LinearLayout> \ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
new file mode 100644
index 000000000000..7b579a1e3554
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class DialogListActivity extends AppCompatActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ListView listView = new ListView(this);
+ listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+ TrivialListActivity.buildStringList()));
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Dialog");
+ builder.setView(listView);
+ builder.create().show();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
new file mode 100644
index 000000000000..798c226bd235
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class InflatingListActivity extends AppCompatActivity {
+ private ListAdapter createListAdapter() {
+ return new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, TrivialListActivity.buildStringList()) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // pathological getView behavior: drop convertView on the floor to force inflation
+ return super.getView(position, null, parent);
+ }
+ };
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FragmentManager fm = getSupportFragmentManager();
+ if (fm.findFragmentById(android.R.id.content) == null) {
+ ListFragment listFragment = new ListFragment();
+ listFragment.setListAdapter(createListAdapter());
+ fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+ }
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
new file mode 100644
index 000000000000..e39ec03d750f
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ArrayAdapter;
+
+public class ShadowGridActivity extends AppCompatActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FragmentManager fm = getSupportFragmentManager();
+ if (fm.findFragmentById(android.R.id.content) == null) {
+ ListFragment listFragment = new ListFragment() {
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setDivider(null);
+ }
+ };
+
+ listFragment.setListAdapter(new ArrayAdapter<>(this,
+ R.layout.card_row, R.id.card_text, TrivialListActivity.buildStringList()));
+ fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+ }
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
index 0af34717f82d..9c8ae9bcceea 100644
--- a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
@@ -47,7 +47,7 @@ public class TrivialListActivity extends AppCompatActivity {
FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentById(android.R.id.content) == null) {
ListFragment listFragment = new ListFragment();
- listFragment.setListAdapter(new ArrayAdapter<>(TrivialListActivity.this,
+ listFragment.setListAdapter(new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, buildStringList()));
fm.beginTransaction().add(android.R.id.content, listFragment).commit();
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 6177784a17c5..95f676e08895 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -32,7 +32,7 @@ import junit.framework.TestCase;
*/
public class WindowManagerPermissionTests extends TestCase {
IWindowManager mWm;
-
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -51,7 +51,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.resumeKeyDispatching(null);
fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
@@ -61,7 +61,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setEventDispatching(true);
fail("IWindowManager.setEventDispatching did not throw SecurityException as"
@@ -71,7 +71,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.addWindowToken(null, 0);
fail("IWindowManager.addWindowToken did not throw SecurityException as"
@@ -81,7 +81,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.removeWindowToken(null);
fail("IWindowManager.removeWindowToken did not throw SecurityException as"
@@ -91,9 +91,10 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
- mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null);
+ mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
+ Configuration.EMPTY);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -101,9 +102,9 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
- mWm.setAppTask(null, 0, null);
+ mWm.setAppTask(null, 0, null, null);
fail("IWindowManager.setAppGroupId did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -111,7 +112,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.updateOrientationFromAppTokens(new Configuration(), null);
fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -121,7 +122,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppOrientation(null, 0);
mWm.addWindowToken(null, 0);
@@ -132,7 +133,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setFocusedApp(null, false);
fail("IWindowManager.setFocusedApp did not throw SecurityException as"
@@ -142,7 +143,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.prepareAppTransition(0, false);
fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
@@ -152,7 +153,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.executeAppTransition();
fail("IWindowManager.executeAppTransition did not throw SecurityException as"
@@ -162,7 +163,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
@@ -172,7 +173,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppWillBeHidden(null);
fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
@@ -182,7 +183,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAppVisibility(null, false);
fail("IWindowManager.setAppVisibility did not throw SecurityException as"
@@ -192,7 +193,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.startAppFreezingScreen(null, 0);
fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
@@ -202,7 +203,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.stopAppFreezingScreen(null, false);
fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
@@ -212,7 +213,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.removeAppToken(null);
fail("IWindowManager.removeAppToken did not throw SecurityException as"
@@ -236,7 +237,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.reenableKeyguard(token);
fail("IWindowManager.reenableKeyguard did not throw SecurityException as"
@@ -246,7 +247,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.exitKeyguardSecurely(null);
fail("IWindowManager.exitKeyguardSecurely did not throw SecurityException as"
@@ -257,7 +258,7 @@ public class WindowManagerPermissionTests extends TestCase {
fail("Unexpected remote exception");
}
}
-
+
@SmallTest
public void testSET_ANIMATION_SCALE() {
try {
@@ -269,7 +270,7 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
+
try {
mWm.setAnimationScales(new float[1]);
fail("IWindowManager.setAnimationScales did not throw SecurityException as"
@@ -280,7 +281,7 @@ public class WindowManagerPermissionTests extends TestCase {
fail("Unexpected remote exception");
}
}
-
+
@SmallTest
public void testSET_ORIENTATION() {
try {
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 769e2a172ce8..b7014454771c 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -54,7 +54,6 @@ aaptTests := \
tests/ResourceFilter_test.cpp \
tests/ResourceTable_test.cpp
-aaptHostLdLibs :=
aaptHostStaticLibs := \
libandroidfw \
libpng \
@@ -68,17 +67,13 @@ aaptHostStaticLibs := \
aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER_FROM_FILE)\"
aaptCFlags += -Wall -Werror
-ifeq ($(HOST_OS),linux)
- aaptHostLdLibs += -lrt -ldl -lpthread
-endif
+aaptHostLdLibs_linux := -lrt -ldl -lpthread
# Statically link libz for MinGW (Win SDK under Linux),
# and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
- aaptHostStaticLibs += libz
-else
- aaptHostLdLibs += -lz
-endif
+aaptHostStaticLibs_windows := libz
+aaptHostLdLibs_linux += -lz
+aaptHostLdLibs_darwin := -lz
# ==========================================================
@@ -87,13 +82,13 @@ endif
include $(CLEAR_VARS)
LOCAL_MODULE := libaapt
-LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-ifeq (darwin,$(HOST_OS))
-LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
-endif
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_CFLAGS_darwin := -D_DARWIN_UNLIMITED_STREAMS
LOCAL_SRC_FILES := $(aaptSources)
-LOCAL_STATIC_LIBRARIES += $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -103,11 +98,14 @@ include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := aapt
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
LOCAL_SRC_FILES := $(aaptMain)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
include $(BUILD_HOST_EXECUTABLE)
@@ -116,15 +114,16 @@ include $(BUILD_HOST_EXECUTABLE)
# Build the host tests: libaapt_tests
# ==========================================================
include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libaapt_tests
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_SRC_FILES += $(aaptTests)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
+LOCAL_SRC_FILES := $(aaptTests)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index ead5e7ae3439..d7bfccb7a6ce 100644
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_AST_H
-#define AIDL_AST_H
+#ifndef AIDL_AST_H_
+#define AIDL_AST_H_
#include <string>
#include <vector>
@@ -368,4 +368,4 @@ struct Document
virtual void Write(FILE* to);
};
-#endif // AIDL_AST_H
+#endif // AIDL_AST_H_
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index efd60a2cda99..542f272d8af7 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -6,24 +6,66 @@
ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
LOCAL_PATH:= $(call my-dir)
+
+# Logic shared between aidl and its unittests
include $(CLEAR_VARS)
+LOCAL_MODULE := libaidl-common
+
+LOCAL_CLANG_CFLAGS := -Wall -Werror
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS += -Wno-unused-parameter
+# yacc dumps a lot of code *just in case*.
+LOCAL_CLANG_CFLAGS += -Wno-unused-function
+LOCAL_CLANG_CFLAGS += -Wno-unneeded-internal-declaration
+# yacc is a tool from a more civilized age.
+LOCAL_CLANG_CFLAGS += -Wno-deprecated-register
+# yacc also has a habit of using char* over const char*.
+LOCAL_CLANG_CFLAGS += -Wno-writable-strings
LOCAL_SRC_FILES := \
- aidl_language_l.l \
- aidl_language_y.y \
- aidl.cpp \
- aidl_language.cpp \
- options.cpp \
- search_path.cpp \
- AST.cpp \
- Type.cpp \
- generate_java.cpp \
- generate_java_binder.cpp \
- generate_java_rpc.cpp
-
-LOCAL_CFLAGS := -g
+ AST.cpp \
+ Type.cpp \
+ aidl.cpp \
+ aidl_language.cpp \
+ aidl_language_l.l \
+ aidl_language_y.y \
+ generate_java.cpp \
+ generate_java_binder.cpp \
+ generate_java_rpc.cpp \
+ options.cpp \
+ search_path.cpp \
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# aidl executable
+include $(CLEAR_VARS)
LOCAL_MODULE := aidl
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := main.cpp
+LOCAL_STATIC_LIBRARIES := libaidl-common
include $(BUILD_HOST_EXECUTABLE)
+
+# Unit tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_unittests
+
+LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror
+LOCAL_SRC_FILES := \
+ options_unittest.cpp \
+ test_main.cpp \
+ tests/test.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+ libaidl-common \
+ libgmock_host \
+ libgtest_host \
+
+LOCAL_LDLIBS_linux := -lrt
+
+include $(BUILD_HOST_NATIVE_TEST)
+
endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index ae12720142e8..d799fca1b752 100644
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_TYPE_H
-#define AIDL_TYPE_H
+#ifndef AIDL_TYPE_H_
+#define AIDL_TYPE_H_
#include "AST.h"
#include <string>
@@ -539,4 +539,4 @@ extern Expression* FALSE_VALUE;
void register_base_types();
-#endif // AIDL_TYPE_H
+#endif // AIDL_TYPE_H_
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 438007f527d5..a4ecb758046e 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -162,11 +162,6 @@ import_import_parsed(buffer_type* statement)
{
}
-static ParserCallbacks g_importCallbacks = {
- &main_document_parsed,
- &import_import_parsed
-};
-
// ==========================================================
static int
check_filename(const char* filename, const char* package, buffer_type* name)
@@ -938,7 +933,7 @@ check_and_assign_method_ids(const char * filename, interface_item_type* first_it
}
// ==========================================================
-static int
+int
compile_aidl(Options& options)
{
int err = 0, N;
@@ -1068,7 +1063,7 @@ compile_aidl(Options& options)
return err;
}
-static int
+int
preprocess_aidl(const Options& options)
{
vector<string> lines;
@@ -1140,24 +1135,3 @@ preprocess_aidl(const Options& options)
close(fd);
return 0;
}
-
-// ==========================================================
-int
-main(int argc, const char **argv)
-{
- Options options;
- int result = parse_options(argc, argv, &options);
- if (result) {
- return result;
- }
-
- switch (options.task)
- {
- case COMPILE_AIDL:
- return compile_aidl(options);
- case PREPROCESS_AIDL:
- return preprocess_aidl(options);
- }
- fprintf(stderr, "aidl: internal error\n");
- return 1;
-}
diff --git a/tools/aidl/aidl.h b/tools/aidl/aidl.h
new file mode 100644
index 000000000000..98b15f36c21a
--- /dev/null
+++ b/tools/aidl/aidl.h
@@ -0,0 +1,9 @@
+#ifndef AIDL_AIDL_H_
+#define AIDL_AIDL_H_
+
+#include "options.h"
+
+int compile_aidl(Options& options);
+int preprocess_aidl(const Options& options);
+
+#endif // AIDL_AIDL_H_
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index de1370c086f5..1be5a9bbeb6d 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
-#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#ifndef AIDL_AIDL_LANGUAGE_H_
+#define AIDL_AIDL_LANGUAGE_H_
typedef enum {
@@ -169,4 +169,4 @@ void init_buffer_type(buffer_type* buf, int lineno);
#endif
-#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 4bfcfeba07c8..ae7983fcffe7 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -1,5 +1,5 @@
-#ifndef GENERATE_JAVA_H
-#define GENERATE_JAVA_H
+#ifndef AIDL_GENERATE_JAVA_H_
+#define AIDL_GENERATE_JAVA_H_
#include "aidl_language.h"
#include "AST.h"
@@ -29,5 +29,5 @@ private:
int m_index;
};
-#endif // GENERATE_JAVA_H
+#endif // AIDL_GENERATE_JAVA_H_
diff --git a/tools/aidl/main.cpp b/tools/aidl/main.cpp
new file mode 100644
index 000000000000..7cc2198bb5df
--- /dev/null
+++ b/tools/aidl/main.cpp
@@ -0,0 +1,23 @@
+#include "aidl.h"
+#include "options.h"
+
+#include <stdio.h>
+
+int
+main(int argc, const char **argv)
+{
+ Options options;
+ int result = parse_options(argc, argv, &options);
+ if (result) {
+ return result;
+ }
+
+ switch (options.task) {
+ case COMPILE_AIDL:
+ return compile_aidl(options);
+ case PREPROCESS_AIDL:
+ return preprocess_aidl(options);
+ }
+ fprintf(stderr, "aidl: internal error\n");
+ return 1;
+}
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 7b2daebec09e..52b0972a89ee 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -48,10 +48,6 @@ parse_options(int argc, const char* const* argv, Options *options)
return 0;
}
- options->task = COMPILE_AIDL;
- options->failOnParcelable = false;
- options->autoDepFile = false;
-
// OPTIONS
while (i < argc) {
const char* s = argv[i];
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index 387e37d08732..4e95e1162836 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_H
-#define DEVICE_TOOLS_AIDL_H
+#ifndef AIDL_OPTIONS_H_
+#define AIDL_OPTIONS_H_
#include <string.h>
#include <string>
@@ -15,15 +15,15 @@ enum {
// This struct is the parsed version of the command line options
struct Options
{
- int task;
- bool failOnParcelable;
+ int task{COMPILE_AIDL};
+ bool failOnParcelable{false};
vector<string> importPaths;
vector<string> preprocessedFiles;
string inputFileName;
string outputFileName;
string outputBaseFolder;
string depFileName;
- bool autoDepFile;
+ bool autoDepFile{false};
vector<string> filesToPreprocess;
};
@@ -33,4 +33,4 @@ struct Options
// It also prints the usage statement on failure.
int parse_options(int argc, const char* const* argv, Options *options);
-#endif // DEVICE_TOOLS_AIDL_H
+#endif // AIDL_OPTIONS_H_
diff --git a/tools/aidl/options_unittest.cpp b/tools/aidl/options_unittest.cpp
new file mode 100644
index 000000000000..fec7f877d02a
--- /dev/null
+++ b/tools/aidl/options_unittest.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "options.h"
+
+using std::vector;
+using std::string;
+
+const char kPreprocessCommandOutputFile[] = "output_file_name";
+const char kPreprocessCommandInput1[] = "input1";
+const char kPreprocessCommandInput2[] = "input2";
+const char kPreprocessCommandInput3[] = "input3";
+const char* kPreprocessCommand[] = {
+ "aidl", "--preprocess",
+ kPreprocessCommandOutputFile,
+ kPreprocessCommandInput1,
+ kPreprocessCommandInput2,
+ kPreprocessCommandInput3,
+};
+
+TEST(OptionsTests, ParsesPreprocess) {
+ Options options;
+ const int argc = sizeof(kPreprocessCommand) / sizeof(*kPreprocessCommand);
+ EXPECT_EQ(parse_options(argc, kPreprocessCommand, &options), 0);
+ EXPECT_EQ(options.task, PREPROCESS_AIDL);
+ EXPECT_EQ(options.failOnParcelable, false);
+ EXPECT_EQ(options.importPaths.size(), 0u);
+ EXPECT_EQ(options.preprocessedFiles.size(), 0u);
+ EXPECT_EQ(options.inputFileName, string{""});
+ EXPECT_EQ(options.outputFileName, string{kPreprocessCommandOutputFile});
+ EXPECT_EQ(options.autoDepFile, false);
+ const vector<string> expected_input{kPreprocessCommandInput1,
+ kPreprocessCommandInput2,
+ kPreprocessCommandInput3};
+ EXPECT_EQ(options.filesToPreprocess, expected_input);
+}
diff --git a/tools/aidl/os.h b/tools/aidl/os.h
index 79d2c35eea3d..752ed4777b0c 100644
--- a/tools/aidl/os.h
+++ b/tools/aidl/os.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
-#define _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
+#ifndef AIDL_OS_H_
+#define AIDL_OS_H_
#if defined(_WIN32)
#define OS_PATH_SEPARATOR '\\'
@@ -23,4 +23,4 @@
#define OS_PATH_SEPARATOR '/'
#endif
-#endif
+#endif // AIDL_OS_H_
diff --git a/tools/aidl/search_path.h b/tools/aidl/search_path.h
index 2bf94b12bbf1..4fec257557de 100644
--- a/tools/aidl/search_path.h
+++ b/tools/aidl/search_path.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+#ifndef AIDL_SEARCH_PATH_H_
+#define AIDL_SEARCH_PATH_H_
#include <stdio.h>
@@ -19,5 +19,4 @@ char* find_import_file(const char* given);
void set_import_paths(const vector<string>& importPaths);
#endif
-#endif // DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-
+#endif // AIDL_SEARCH_PATH_H_
diff --git a/tools/aidl/test_main.cpp b/tools/aidl/test_main.cpp
new file mode 100644
index 000000000000..4d820af774e1
--- /dev/null
+++ b/tools/aidl/test_main.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tools/aidl/tests/test.cpp b/tools/aidl/tests/test.cpp
new file mode 100644
index 000000000000..15ae294138a8
--- /dev/null
+++ b/tools/aidl/tests/test.cpp
@@ -0,0 +1,3 @@
+#include <gtest/gtest.h>
+
+TEST(DummyCase, DummyTest) {}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index a8fd91c3a607..ed8b56e1e601 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -74,11 +74,10 @@ public class IWindowManagerImpl implements IWindowManager {
// ---- unused implementation of IWindowManager ----
@Override
- public Configuration addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11) throws RemoteException {
+ Rect arg11, Configuration arg12) throws RemoteException {
// TODO Auto-generated method stub
- return Configuration.EMPTY;
}
@Override
@@ -315,9 +314,9 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public Configuration setAppTask(IBinder arg0, int arg1, Rect arg2) throws RemoteException {
+ public void setAppTask(IBinder arg0, int arg1, Rect arg2, Configuration arg3)
+ throws RemoteException {
// TODO Auto-generated method stub
- return Configuration.EMPTY;
}
@Override
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index d9ddf08862b3..239bed589412 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -43,7 +43,6 @@ cIncludes := \
external/zlib \
frameworks/base/tools
-hostLdLibs :=
hostStaticLibs := \
libaapt \
libandroidfw \
@@ -57,17 +56,13 @@ hostStaticLibs := \
cFlags := -Wall -Werror
-ifeq ($(HOST_OS),linux)
- hostLdLibs += -lrt -ldl -lpthread
-endif
+hostLdLibs_linux := -lrt -ldl -lpthread
# Statically link libz for MinGW (Win SDK under Linux),
# and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
- hostStaticLibs += libz
-else
- hostLdLibs += -lz
-endif
+hostStaticLibs_windows := libz
+hostLdLibs_darwin := -lz
+hostLdLibs_linux += -lz
# ==========================================================
@@ -75,11 +70,12 @@ endif
# ==========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libsplit-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_SRC_FILES := $(sources)
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_CFLAGS := $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -93,10 +89,12 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(testSources)
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
include $(BUILD_HOST_NATIVE_TEST)
@@ -105,13 +103,16 @@ include $(BUILD_HOST_NATIVE_TEST)
# ==========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := split-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_SRC_FILES := $(main)
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
include $(BUILD_HOST_EXECUTABLE)